Commit - 20250414-165250947

This commit is contained in:
Flatlogic Bot 2025-04-14 16:53:09 +00:00
parent 8e5fd526d9
commit 4846e3892d
47 changed files with 106 additions and 6672 deletions

View File

@ -1,3 +0,0 @@
backend/node_modules
frontend/node_modules
frontend/build

6
.gitignore vendored
View File

@ -1,6 +0,0 @@
/backend/node_modules
/frontend/node_modules
node_modules/
*/node_modules/
**/node_modules/
*/build/

View File

@ -1,6 +1,6 @@
# Test555
# Test 444
## This project was generated by [Flatlogic Platform](https://flatlogic.com).

View File

@ -1,26 +0,0 @@
const globals = require('globals');
module.exports = [
{
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
languageOptions: {
ecmaVersion: 2021,
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
},
parser: '@typescript-eslint/parser',
},
plugins: ['@typescript-eslint'],
rules: {
'no-unused-vars': 'warn',
'no-console': 'off',
'indent': ['error', 2],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'@typescript-eslint/no-unused-vars': 'warn',
},
},
];

View File

@ -1,11 +0,0 @@
{
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80,
"trailingComma": "all",
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always"
}

View File

@ -1,7 +0,0 @@
const path = require('path');
module.exports = {
"config": path.resolve("src", "db", "db.config.js"),
"models-path": path.resolve("src", "db", "models"),
"seeders-path": path.resolve("src", "db", "seeders"),
"migrations-path": path.resolve("src", "db", "migrations")
};

View File

@ -1,23 +0,0 @@
FROM node:20.15.1-alpine
RUN apk update && apk add bash
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN yarn install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 4000
CMD [ "yarn", "start" ]

View File

@ -1,13 +0,0 @@
#test - template backend,
#### Run App on local machine:
##### Install local dependencies:
- `yarn install`
---
##### Start build:
- `yarn start`

View File

@ -1,42 +0,0 @@
{
"name": "app-shell",
"description": "app-shell",
"scripts": {
"start": "node ./src/index.js"
},
"dependencies": {
"@babel/parser": "^7.26.7",
"adm-zip": "^0.5.16",
"axios": "^1.6.7",
"bcrypt": "5.1.1",
"cors": "2.8.5",
"eslint": "^9.13.0",
"express": "4.18.2",
"formidable": "1.2.2",
"helmet": "4.1.1",
"json2csv": "^5.0.7",
"jsonwebtoken": "8.5.1",
"lodash": "4.17.21",
"moment": "2.30.1",
"multer": "^1.4.4",
"passport": "^0.7.0",
"passport-google-oauth2": "^0.2.0",
"passport-jwt": "^4.0.1",
"passport-microsoft": "^0.1.0",
"postcss": "^8.5.1",
"sequelize-json-schema": "^2.1.1",
"pg": "^8.13.3"
},
"engines": {
"node": ">=18"
},
"private": true,
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.12.2",
"@typescript-eslint/parser": "^8.12.2",
"cross-env": "7.0.3",
"mocha": "8.1.3",
"nodemon": "^3.1.7",
"sequelize-cli": "6.6.2"
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,16 +0,0 @@
const config = {
schema_encryption_key: process.env.SCHEMA_ENCRYPTION_KEY || '',
project_uuid: 'd346520e-34c8-4488-890d-8254d64f8607',
flHost: process.env.NODE_ENV === 'production' ? 'https://flatlogic.com/projects' : 'http://localhost:3000/projects',
gitea_domain: process.env.GITEA_DOMAIN || 'gitea.flatlogic.app',
gitea_username: process.env.GITEA_USERNAME || 'admin',
gitea_api_token: process.env.GITEA_API_TOKEN || null,
github_repo_url: process.env.GITHUB_REPO_URL || null,
github_token: process.env.GITHUB_TOKEN || null,
};
module.exports = config;

View File

@ -1,23 +0,0 @@
const jwt = require('jsonwebtoken');
const config = require('./config');
module.exports = class Helpers {
static wrapAsync(fn) {
return function (req, res, next) {
fn(req, res, next).catch(next);
};
}
static commonErrorHandler(error, req, res, next) {
if ([400, 403, 404].includes(error.code)) {
return res.status(error.code).send(error.message);
}
console.error(error);
return res.status(500).send(error.message);
}
static jwtSign(data) {
return jwt.sign(data, config.secret_key, { expiresIn: '6h' });
}
};

View File

@ -1,54 +0,0 @@
const express = require('express');
const cors = require('cors');
const app = express();
const bodyParser = require('body-parser');
const checkPermissions = require('./middlewares/check-permissions');
const modifyPath = require('./middlewares/modify-path');
const VCS = require('./services/vcs');
const executorRoutes = require('./routes/executor');
const vcsRoutes = require('./routes/vcs');
// Function to initialize the Git repository
function initRepo() {
const projectId = '30719';
return VCS.initRepo(projectId);
}
// Start the Express app on APP_SHELL_PORT (4000)
function startServer() {
const PORT = 4000;
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
}
// Run Git check after the server is up
function runGitCheck() {
initRepo()
.then(result => {
console.log(result?.message ? result.message : result);
// Here you can add additional logic if needed
})
.catch(err => {
console.error('Error during repo initialization:', err);
// Optionally exit the process if Git check is critical:
// process.exit(1);
});
}
app.use(cors({ origin: true }));
app.use(bodyParser.json());
app.use(checkPermissions);
app.use(modifyPath);
app.use('/executor', executorRoutes);
app.use('/vcs', vcsRoutes);
// Start the app_shell server
startServer();
// Now perform Git check
runGitCheck();
module.exports = app;

View File

@ -1,17 +0,0 @@
const config = require('../config');
function checkPermissions(req, res, next) {
const project_uuid = config.project_uuid;
const requiredHeader = 'X-Project-UUID';
const headerValue = req.headers[requiredHeader.toLowerCase()];
// Logging whatever request we're getting
console.log('Request:', req.url, req.method, req.body, req.headers);
if (headerValue && headerValue === project_uuid) {
next();
} else {
res.status(403).send({ error: 'Stop right there, criminal scum! Your project UUID is invalid or missing.' });
}
}
module.exports = checkPermissions;

View File

@ -1,8 +0,0 @@
function modifyPath(req, res, next) {
if (req.body && req.body.path) {
req.body.path = '../../../' + req.body.path;
}
next();
}
module.exports = modifyPath;

View File

@ -1,312 +0,0 @@
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const fs = require('fs');
const ExecutorService = require('../services/executor');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
router.post(
'/read_project_tree',
wrapAsync(async (req, res) => {
const { path } = req.body;
const tree = await ExecutorService.readProjectTree(path);
res.status(200).send(tree);
}),
);
router.post(
'/read_file',
wrapAsync(async (req, res) => {
const { path, showLines } = req.body;
const content = await ExecutorService.readFileContents(path, showLines);
res.status(200).send(content);
}),
);
router.post(
'/count_file_lines',
wrapAsync(async (req, res) => {
const { path } = req.body;
const content = await ExecutorService.countFileLines(path);
res.status(200).send(content);
}),
);
// router.post(
// '/read_file_header',
// wrapAsync(async (req, res) => {
// const { path, N } = req.body;
// try {
// const header = await ExecutorService.readFileHeader(path, N);
// res.status(200).send(header);
// } catch (error) {
// res.status(500).send({
// error: true,
// message: error.message,
// details: error.details || error.stack,
// validation: error.validation
// });
// }
// }),
// );
router.post(
'/read_file_line_context',
wrapAsync(async (req, res) => {
const { path, lineNumber, windowSize, showLines } = req.body;
try {
const context = await ExecutorService.readFileLineContext(path, lineNumber, windowSize, showLines);
res.status(200).send(context);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/write_file',
wrapAsync(async (req, res) => {
const { path, fileContents, comment } = req.body;
try {
await ExecutorService.writeFile(path, fileContents, comment);
res.status(200).send({ message: 'File written successfully' });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/insert_file_content',
wrapAsync(async (req, res) => {
const { path, lineNumber, newContent, message } = req.body;
try {
await ExecutorService.insertFileContent(path, lineNumber, newContent, message);
res.status(200).send({ message: 'File written successfully' });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/replace_file_line',
wrapAsync(async (req, res) => {
const { path, lineNumber, newText } = req.body;
try {
const result = await ExecutorService.replaceFileLine(path, lineNumber, newText);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/replace_file_chunk',
wrapAsync(async (req, res) => {
const { path, startLine, endLine, newCode } = req.body;
try {
const result = await ExecutorService.replaceFileChunk(path, startLine, endLine, newCode);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/delete_file_lines',
wrapAsync(async (req, res) => {
const { path, startLine, endLine, message } = req.body;
try {
const result = await ExecutorService.deleteFileLines(path, startLine, endLine, message);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/validate_file',
wrapAsync(async (req, res) => {
const { path } = req.body;
try {
const validationResult = await ExecutorService.validateFile(path);
res.status(200).send({ validationResult });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/check_frontend_runtime_error',
wrapAsync(async (req, res) => {
try {
const result = await ExecutorService.checkFrontendRuntimeLogs();
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/replace_code_block',
wrapAsync(async (req, res) => {
const {path, oldCode, newCode, message} = req.body;
try {
const response = await ExecutorService.replaceCodeBlock(path, oldCode, newCode, message);
res.status(200).send(response);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
})
}
})
)
router.post('/update_project_files_from_scheme',
upload.single('file'), // 'file' - name of the field in the form
async (req, res) => {
console.log('Request received');
console.log('Headers:', req.headers);
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' });
}
console.log('File info:', {
originalname: req.file.originalname,
path: req.file.path,
size: req.file.size,
mimetype: req.file.mimetype
});
try {
console.log('Starting update process...');
const result = await ExecutorService.updateProjectFilesFromScheme(req.file.path);
console.log('Update completed, result:', result);
console.log('Removing temp file...');
fs.unlinkSync(req.file.path);
console.log('Temp file removed');
console.log('Sending response...');
return res.json(result);
} catch (error) {
console.error('Error in route handler:', error);
if (req.file) {
try {
fs.unlinkSync(req.file.path);
console.log('Temp file removed after error');
} catch (unlinkError) {
console.error('Error removing temp file:', unlinkError);
}
}
console.error('Update project files error:', error);
return res.status(500).json({
error: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
}
}
);
router.post(
'/get_db_schema',
wrapAsync(async (req, res) => {
try {
const jsonSchema = await ExecutorService.getDBSchema();
res.status(200).send({ jsonSchema });
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/execute_sql',
wrapAsync(async (req, res) => {
try {
const { query } = req.body;
const result = await ExecutorService.executeSQL(query);
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/search_files',
wrapAsync(async (req, res) => {
try {
const { searchStrings } = req.body;
if (
typeof searchStrings !== 'string' &&
!(
Array.isArray(searchStrings) &&
searchStrings.every(item => typeof item === 'string')
)
) {
return res.status(400).send({ error: 'searchStrings must be a string or an array of strings' });
}
const result = await ExecutorService.searchFiles(searchStrings);
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error.message });
}
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -1,40 +0,0 @@
const express = require('express');
const wrapAsync = require('../helpers').wrapAsync; // Ваша обёртка для обработки асинхронных маршрутов
const VSC = require('../services/vcs');
const router = express.Router();
router.post('/init', wrapAsync(async (req, res) => {
const result = await VSC.initRepo();
res.status(200).send(result);
}));
router.post('/commit', wrapAsync(async (req, res) => {
const { message, files, dev_schema } = req.body;
const result = await VSC.commitChanges(message, files, dev_schema);
res.status(200).send(result);
}));
router.post('/log', wrapAsync(async (req, res) => {
const result = await VSC.getLog();
res.status(200).send(result);
}));
router.post('/rollback', wrapAsync(async (req, res) => {
const { ref } = req.body;
// const result = await VSC.checkout(ref);
const result = await VSC.revert(ref);
res.status(200).send(result);
}));
router.post('/sync-to-stable', wrapAsync(async (req, res) => {
const result = await VSC.mergeDevIntoMaster();
res.status(200).send(result);
}));
router.post('/reset-dev', wrapAsync(async (req, res) => {
const result = await VSC.resetDevBranch();
res.status(200).send(result);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -1,88 +0,0 @@
// Database.js
const { Client } = require('pg');
const config = require('../../../backend/src/db/db.config');
const env = process.env.NODE_ENV || 'development';
const dbConfig = config[env];
class Database {
constructor() {
this.client = new Client({
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
host: dbConfig.host,
port: dbConfig.port
});
// Connect once, reuse the client
this.client.connect().catch(err => {
console.error('Error connecting to the database:', err);
throw err;
});
}
async executeSQL(query) {
try {
const result = await this.client.query(query);
return {
success: true,
rows: result.rows
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
// Method to fetch simple table/column info from 'information_schema'
// (You can expand this to handle constraints, indexes, etc.)
async getDBSchema(schemaName = 'public') {
try {
const tableQuery = `
SELECT table_name
FROM information_schema.tables
WHERE table_schema = $1
AND table_type = 'BASE TABLE'
ORDER BY table_name
`;
const columnQuery = `
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = $1
ORDER BY table_name, ordinal_position
`;
const [tablesResult, columnsResult] = await Promise.all([
this.client.query(tableQuery, [schemaName]),
this.client.query(columnQuery, [schemaName]),
]);
// Build a simple schema object:
const tables = tablesResult.rows.map(row => row.table_name);
const columnsByTable = {};
columnsResult.rows.forEach(row => {
const { table_name, column_name, data_type, is_nullable } = row;
if (!columnsByTable[table_name]) columnsByTable[table_name] = [];
columnsByTable[table_name].push({ column_name, data_type, is_nullable });
});
// Combine tables with their columns
return tables.map(table => ({
table,
columns: columnsByTable[table] || [],
}));
} catch (error) {
console.error('Error fetching schema:', error);
throw error;
}
}
async close() {
await this.client.end();
}
}
module.exports = new Database();

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
const { getNotification, isNotification } = require('../helpers');
module.exports = class ForbiddenError extends Error {
constructor(messageCode) {
let message;
if (messageCode && isNotification(messageCode)) {
message = getNotification(messageCode);
}
message = message || getNotification('errors.forbidden.message');
super(message);
this.code = 403;
}
};

View File

@ -1,16 +0,0 @@
const { getNotification, isNotification } = require('../helpers');
module.exports = class ValidationError extends Error {
constructor(messageCode) {
let message;
if (messageCode && isNotification(messageCode)) {
message = getNotification(messageCode);
}
message = message || getNotification('errors.validation.message');
super(message);
this.code = 400;
}
};

View File

@ -1,30 +0,0 @@
const _get = require('lodash/get');
const errors = require('./list');
function format(message, args) {
if (!message) {
return null;
}
return message.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
}
const isNotification = (key) => {
const message = _get(errors, key);
return !!message;
};
const getNotification = (key, ...args) => {
const message = _get(errors, key);
if (!message) {
return key;
}
return format(message, args);
};
exports.getNotification = getNotification;
exports.isNotification = isNotification;

View File

@ -1,100 +0,0 @@
const errors = {
app: {
title: 'test',
},
auth: {
userDisabled: 'Your account is disabled',
forbidden: 'Forbidden',
unauthorized: 'Unauthorized',
userNotFound: `Sorry, we don't recognize your credentials`,
wrongPassword: `Sorry, we don't recognize your credentials`,
weakPassword: 'This password is too weak',
emailAlreadyInUse: 'Email is already in use',
invalidEmail: 'Please provide a valid email',
passwordReset: {
invalidToken: 'Password reset link is invalid or has expired',
error: `Email not recognized`,
},
passwordUpdate: {
samePassword: `You can't use the same password. Please create new password`,
},
userNotVerified: `Sorry, your email has not been verified yet`,
emailAddressVerificationEmail: {
invalidToken: 'Email verification link is invalid or has expired',
error: `Email not recognized`,
},
},
iam: {
errors: {
userAlreadyExists: 'User with this email already exists',
userNotFound: 'User not found',
disablingHimself: `You can't disable yourself`,
revokingOwnPermission: `You can't revoke your own owner permission`,
deletingHimself: `You can't delete yourself`,
emailRequired: 'Email is required',
},
},
importer: {
errors: {
invalidFileEmpty: 'The file is empty',
invalidFileExcel: 'Only excel (.xlsx) files are allowed',
invalidFileUpload:
'Invalid file. Make sure you are using the last version of the template.',
importHashRequired: 'Import hash is required',
importHashExistent: 'Data has already been imported',
userEmailMissing: 'Some items in the CSV do not have an email',
},
},
errors: {
forbidden: {
message: 'Forbidden',
},
validation: {
message: 'An error occurred',
},
searchQueryRequired: {
message: 'Search query is required',
},
},
emails: {
invitation: {
subject: `You've been invited to {0}`,
body: `
<p>Hello,</p>
<p>You've been invited to {0} set password for your {1} account.</p>
<p><a href='{2}'>{2}</a></p>
<p>Thanks,</p>
<p>Your {0} team</p>
`,
},
emailAddressVerification: {
subject: `Verify your email for {0}`,
body: `
<p>Hello,</p>
<p>Follow this link to verify your email address.</p>
<p><a href='{0}'>{0}</a></p>
<p>If you didn't ask to verify this address, you can ignore this email.</p>
<p>Thanks,</p>
<p>Your {1} team</p>
`,
},
passwordReset: {
subject: `Reset your password for {0}`,
body: `
<p>Hello,</p>
<p>Follow this link to reset your {0} password for your {1} account.</p>
<p><a href='{2}'>{2}</a></p>
<p>If you didn't ask to reset your password, you can ignore this email.</p>
<p>Thanks,</p>
<p>Your {0} team</p>
`,
},
},
};
module.exports = errors;

View File

@ -1,67 +0,0 @@
const axios = require('axios');
const config = require('../config.js');
class ProjectEventsService {
/**
* Sends a project event to the Rails backend
*
* @param {string} eventType - Type of the event
* @param {object} payload - Event payload data
* @param {object} options - Additional options
* @param {string} [options.conversationId] - Optional conversation ID
* @param {boolean} [options.isError=false] - Whether this is an error event
* @returns {Promise<object>} - Response from the webhook
*/
static async sendEvent(eventType, payload = {}, options = {}) {
try {
console.log(`[DEBUG] Sending project event: ${eventType}`);
const webhookUrl = `https://flatlogic.com/projects/events_webhook`;
// Prepare the event data
const eventData = {
project_uuid: config.project_uuid,
event_type: eventType,
payload: {
...payload,
message: `[APP] ${payload.message}`,
is_error: options.isError || false,
system_message: true,
is_command_info: true
}
};
// Add conversation ID if provided
if (options.conversationId) {
eventData.conversation_id = options.conversationId;
}
const headers = {
'Content-Type': 'application/json',
'x-project-uuid': config.project_uuid
};
console.log(`[DEBUG] Event data: ${JSON.stringify(eventData)}`);
const response = await axios.post(webhookUrl, eventData, { headers });
console.log(`[DEBUG] Event sent successfully, status: ${response.status}`);
return response.data;
} catch (error) {
console.error(`[ERROR] Failed to send project event: ${error.message}`);
if (error.response) {
console.error(`[ERROR] Response status: ${error.response.status}`);
console.error(`[ERROR] Response data: ${JSON.stringify(error.response.data)}`);
}
// Don't throw the error, just return a failed status
// This prevents errors in the event service from breaking app functionality
return {
success: false,
error: error.message
};
}
}
}
module.exports = ProjectEventsService;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#Test555 - template backend,
#Test 444 - template backend,
#### Run App on local machine:
@ -38,10 +38,10 @@
- Type this command to creating a new database.
- `postgres=> CREATE DATABASE db_test555;`
- `postgres=> CREATE DATABASE db_test_444;`
- Then give that new user privileges to the new database then quit the `psql`.
- `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_test555 TO admin;`
- `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_test_444 TO admin;`
- `postgres=> \q`
---

View File

@ -1,6 +1,6 @@
{
"name": "test555",
"description": "Test555 - template backend",
"name": "test444",
"description": "Test 444 - template backend",
"scripts": {
"start": "npm run db:migrate && npm run db:seed && npm run watch",
"db:migrate": "sequelize-cli db:migrate",

View File

@ -36,7 +36,7 @@ const config = {
},
uploadDir: os.tmpdir(),
email: {
from: 'Test555 <app@flatlogic.app>',
from: 'Test 444 <app@flatlogic.app>',
host: 'email-smtp.us-east-1.amazonaws.com',
port: 587,
auth: {

View File

@ -13,7 +13,7 @@ module.exports = {
username: 'postgres',
dialect: 'postgres',
password: '',
database: 'db_test555',
database: 'db_test_444',
host: process.env.DB_HOST || 'localhost',
logging: console.log,
seederStorage: 'sequelize',

View File

@ -43,16 +43,6 @@ const ActivitiesData = [
// type code here for "relation_one" field
},
{
description: 'Contract review with Umbrella Corp',
scheduled_at: new Date('2023-11-04T09:00:00Z'),
// type code here for "relation_one" field
// type code here for "relation_one" field
},
];
const ContactsData = [
@ -91,48 +81,12 @@ const ContactsData = [
// type code here for "relation_one" field
},
{
first_name: 'Diana',
last_name: 'Miller',
email: 'diana.miller@example.com',
// type code here for "relation_one" field
// type code here for "relation_one" field
},
];
const LeadsData = [
{
name: 'Acme Corp',
status: 'qualified',
// type code here for "relation_one" field
// type code here for "relation_one" field
// type code here for "relation_one" field
},
{
name: 'Globex Inc',
status: 'contacted',
// type code here for "relation_one" field
// type code here for "relation_one" field
// type code here for "relation_one" field
},
{
name: 'Initech',
status: 'new',
// type code here for "relation_one" field
@ -143,7 +97,19 @@ const LeadsData = [
},
{
name: 'Umbrella Corp',
name: 'Globex Inc',
status: 'qualified',
// type code here for "relation_one" field
// type code here for "relation_one" field
// type code here for "relation_one" field
},
{
name: 'Initech',
status: 'new',
@ -185,16 +151,6 @@ const MetricsData = [
// type code here for "relation_one" field
},
{
name: 'Marketing ROI',
value: 150,
// type code here for "relation_one" field
// type code here for "relation_one" field
},
];
const NotesData = [
@ -221,14 +177,6 @@ const NotesData = [
// type code here for "relation_one" field
},
{
content: 'Umbrella Corp has budget constraints.',
// type code here for "relation_one" field
// type code here for "relation_one" field
},
];
const BranchesData = [
@ -243,10 +191,6 @@ const BranchesData = [
{
name: 'Suburban Office',
},
{
name: 'Riverside Office',
},
];
// Similar logic for "relation_many"
@ -284,17 +228,6 @@ async function associateUserWithBranch() {
if (User2?.setBranch) {
await User2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const User3 = await Users.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (User3?.setBranch) {
await User3.setBranch(relatedBranch3);
}
}
async function associateActivityWithLead() {
@ -330,17 +263,6 @@ async function associateActivityWithLead() {
if (Activity2?.setLead) {
await Activity2.setLead(relatedLead2);
}
const relatedLead3 = await Leads.findOne({
offset: Math.floor(Math.random() * (await Leads.count())),
});
const Activity3 = await Activities.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Activity3?.setLead) {
await Activity3.setLead(relatedLead3);
}
}
async function associateActivityWithBranch() {
@ -376,17 +298,6 @@ async function associateActivityWithBranch() {
if (Activity2?.setBranch) {
await Activity2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Activity3 = await Activities.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Activity3?.setBranch) {
await Activity3.setBranch(relatedBranch3);
}
}
async function associateContactWithLead() {
@ -422,17 +333,6 @@ async function associateContactWithLead() {
if (Contact2?.setLead) {
await Contact2.setLead(relatedLead2);
}
const relatedLead3 = await Leads.findOne({
offset: Math.floor(Math.random() * (await Leads.count())),
});
const Contact3 = await Contacts.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Contact3?.setLead) {
await Contact3.setLead(relatedLead3);
}
}
async function associateContactWithBranch() {
@ -468,17 +368,6 @@ async function associateContactWithBranch() {
if (Contact2?.setBranch) {
await Contact2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Contact3 = await Contacts.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Contact3?.setBranch) {
await Contact3.setBranch(relatedBranch3);
}
}
async function associateLeadWithOwner() {
@ -514,16 +403,40 @@ async function associateLeadWithOwner() {
if (Lead2?.setOwner) {
await Lead2.setOwner(relatedOwner2);
}
}
const relatedOwner3 = await Users.findOne({
offset: Math.floor(Math.random() * (await Users.count())),
async function associateLeadWithBranch() {
const relatedBranch0 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead3 = await Leads.findOne({
const Lead0 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 3,
offset: 0,
});
if (Lead3?.setOwner) {
await Lead3.setOwner(relatedOwner3);
if (Lead0?.setBranch) {
await Lead0.setBranch(relatedBranch0);
}
const relatedBranch1 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead1 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 1,
});
if (Lead1?.setBranch) {
await Lead1.setBranch(relatedBranch1);
}
const relatedBranch2 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead2 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 2,
});
if (Lead2?.setBranch) {
await Lead2.setBranch(relatedBranch2);
}
}
@ -560,63 +473,6 @@ async function associateLeadWithBranch() {
if (Lead2?.setBranch) {
await Lead2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead3 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Lead3?.setBranch) {
await Lead3.setBranch(relatedBranch3);
}
}
async function associateLeadWithBranch() {
const relatedBranch0 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead0 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 0,
});
if (Lead0?.setBranch) {
await Lead0.setBranch(relatedBranch0);
}
const relatedBranch1 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead1 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 1,
});
if (Lead1?.setBranch) {
await Lead1.setBranch(relatedBranch1);
}
const relatedBranch2 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead2 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 2,
});
if (Lead2?.setBranch) {
await Lead2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Lead3 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Lead3?.setBranch) {
await Lead3.setBranch(relatedBranch3);
}
}
async function associateMetricWithBranch() {
@ -652,17 +508,6 @@ async function associateMetricWithBranch() {
if (Metric2?.setBranch) {
await Metric2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Metric3 = await Metrics.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Metric3?.setBranch) {
await Metric3.setBranch(relatedBranch3);
}
}
async function associateMetricWithBranch() {
@ -698,17 +543,6 @@ async function associateMetricWithBranch() {
if (Metric2?.setBranch) {
await Metric2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Metric3 = await Metrics.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Metric3?.setBranch) {
await Metric3.setBranch(relatedBranch3);
}
}
async function associateNoteWithLead() {
@ -744,17 +578,6 @@ async function associateNoteWithLead() {
if (Note2?.setLead) {
await Note2.setLead(relatedLead2);
}
const relatedLead3 = await Leads.findOne({
offset: Math.floor(Math.random() * (await Leads.count())),
});
const Note3 = await Notes.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Note3?.setLead) {
await Note3.setLead(relatedLead3);
}
}
async function associateNoteWithBranch() {
@ -790,17 +613,6 @@ async function associateNoteWithBranch() {
if (Note2?.setBranch) {
await Note2.setBranch(relatedBranch2);
}
const relatedBranch3 = await Branches.findOne({
offset: Math.floor(Math.random() * (await Branches.count())),
});
const Note3 = await Notes.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (Note3?.setBranch) {
await Note3.setBranch(relatedBranch3);
}
}
module.exports = {

View File

@ -49,9 +49,9 @@ const options = {
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'Test555',
title: 'Test 444',
description:
'Test555 Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
'Test 444 Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
},
servers: [
{

View File

@ -1,6 +1,6 @@
const errors = {
app: {
title: 'Test555',
title: 'Test 444',
},
auth: {

View File

@ -15,7 +15,7 @@ services:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
- POSTGRES_DB=db_test555
- POSTGRES_DB=db_test_444
ports:
- "5432:5432"
backend:

View File

@ -1,4 +1,4 @@
# Test555
# Test 444
## This project was generated by Flatlogic Platform.

View File

@ -75,7 +75,7 @@ export default function AsideMenuLayer({
>
<div className='text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0'>
<Link href={'/home'}>
<b className='font-black'>Test555</b>
<b className='font-black'>Test 444</b>
</Link>
{organizationName && <p>{organizationName}</p>}

View File

@ -19,7 +19,7 @@ export default function WebSiteHeader({
const websiteHeder = useAppSelector((state) => state.style.websiteHeder);
const borders = useAppSelector((state) => state.style.borders);
const style = HeaderStyle.PAGES_RIGHT;
const style = HeaderStyle.PAGES_LEFT;
const design = HeaderDesigns.DESIGN_DIVERSITY;
return (

View File

@ -71,9 +71,9 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
}
}, []);
const title = 'Test555';
const title = 'Test 444';
const description = 'Test555 generated by Flatlogic';
const description = 'Test 444 generated by Flatlogic';
const url = 'https://flatlogic.com/';

View File

@ -27,7 +27,7 @@ import ContactFormSection from '../components/WebPageComponents/ContactFormCompo
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -125,10 +125,10 @@ export default function WebSite() {
content={`Discover our CRM app tailored for the law industry, connecting departments like sales, customer service, and marketing. Streamline your operations and track leads efficiently.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Law professionals collaborating efficiently']}
mainText={`Revolutionize Your Legal Operations Today`}
subTitle={`Experience seamless integration with ${projectName}, the CRM designed for the law industry. Connect departments, track leads, and organize effortlessly.`}
@ -137,9 +137,9 @@ export default function WebSite() {
/>
<FeaturesSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Dashboard showcasing CRM features']}
withBg={0}
withBg={1}
features={features_points}
mainText={`Discover Key Features of ${projectName}`}
subTitle={`Unlock the full potential of your legal operations with ${projectName}. Streamline processes, enhance collaboration, and drive efficiency.`}
@ -147,7 +147,7 @@ export default function WebSite() {
/>
<AboutUsSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Team collaborating in modern office']}
mainText={`Empowering Legal Teams with ${projectName}`}
subTitle={`At ${projectName}, we are dedicated to transforming the way legal professionals work. Our CRM is designed to connect departments, streamline operations, and enhance productivity across the board.`}
@ -156,21 +156,21 @@ export default function WebSite() {
/>
<TestimonialsSection
projectName={'Test555'}
projectName={'Test 444'}
design={TestimonialsDesigns.MULTI_CARD_DISPLAY || ''}
testimonials={testimonials}
mainText={`What Our Clients Say About ${projectName} `}
/>
<ContactFormSection
projectName={'Test555'}
projectName={'Test 444'}
design={ContactFormDesigns.WITH_IMAGE || ''}
image={['Person typing on a laptop']}
mainText={`Get in Touch with ${projectName} `}
subTitle={`Reach out to us anytime. Our team is ready to assist you with any inquiries or support you need. Expect a response within 24 hours.`}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}

View File

@ -50,7 +50,7 @@ export default function Login() {
remember: true,
});
const title = 'Test555';
const title = 'Test 444';
// Fetch Pexels image/video
useEffect(() => {

View File

@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
import { getPageTitle } from '../config';
export default function PrivacyPolicy() {
const title = 'Test555';
const title = 'Test 444';
const [projectUrl, setProjectUrl] = useState('');
useEffect(() => {

View File

@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
import { getPageTitle } from '../config';
export default function PrivacyPolicy() {
const title = 'Test555';
const title = 'Test 444';
const [projectUrl, setProjectUrl] = useState('');
useEffect(() => {

View File

@ -24,7 +24,7 @@ import ContactFormSection from '../../components/WebPageComponents/ContactFormCo
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -101,10 +101,10 @@ export default function WebSite() {
content={`Get to know the team behind ${projectName}. Learn about our mission, values, and how we are transforming the legal industry with our innovative CRM solutions.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Team brainstorming in modern office']}
mainText={`Meet the Visionaries Behind ${projectName}`}
subTitle={`Discover the passion and dedication driving ${projectName}. Our team is committed to revolutionizing the legal industry with cutting-edge CRM solutions.`}
@ -113,7 +113,7 @@ export default function WebSite() {
/>
<AboutUsSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Team members discussing project goals']}
mainText={`Our Journey with ${projectName}`}
subTitle={`At ${projectName}, we are driven by innovation and a commitment to excellence. Our mission is to empower legal professionals with tools that enhance efficiency and collaboration.`}
@ -122,21 +122,21 @@ export default function WebSite() {
/>
<TestimonialsSection
projectName={'Test555'}
projectName={'Test 444'}
design={TestimonialsDesigns.HORIZONTAL_CAROUSEL_DIVERSITY || ''}
testimonials={testimonials}
mainText={`Hear from Our Satisfied Clients `}
/>
<ContactFormSection
projectName={'Test555'}
projectName={'Test 444'}
design={ContactFormDesigns.HIGHLIGHTED || ''}
image={['Person using a smartphone']}
mainText={`Connect with ${projectName} Today `}
subTitle={`We're here to help. Reach out to us anytime, and our team will respond within 24 hours to assist with your inquiries.`}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}

View File

@ -18,7 +18,7 @@ import ContactFormSection from '../../components/WebPageComponents/ContactFormCo
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -62,10 +62,10 @@ export default function WebSite() {
content={`Have questions or need assistance? Contact ${projectName} today. Our team is ready to help you with any inquiries or support you need.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Customer support team assisting clients']}
mainText={`Connect with ${projectName} Today`}
subTitle={`We're here to assist you with any questions or support you need. Reach out to ${projectName} and let us help you enhance your legal operations.`}
@ -74,14 +74,14 @@ export default function WebSite() {
/>
<ContactFormSection
projectName={'Test555'}
projectName={'Test 444'}
design={ContactFormDesigns.WITH_IMAGE || ''}
image={['Person filling out contact form']}
mainText={`Get in Touch with ${projectName} `}
subTitle={`Have questions or need support? Contact us anytime, and our team will respond within 24 hours to assist you.`}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}

View File

@ -18,7 +18,7 @@ import FaqSection from '../../components/WebPageComponents/FaqComponent';
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -100,10 +100,10 @@ export default function WebSite() {
content={`Find answers to common questions about ${projectName}. Learn more about our services, features, and how we can assist your legal practice.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Person reading FAQ on laptop']}
mainText={`Your Questions Answered with ${projectName}`}
subTitle={`Explore our comprehensive FAQ section to find answers to your questions about ${projectName}. Learn how our services can benefit your legal practice.`}
@ -112,13 +112,13 @@ export default function WebSite() {
/>
<FaqSection
projectName={'Test555'}
projectName={'Test 444'}
design={FaqDesigns.ACCORDION || ''}
faqs={faqs}
mainText={`Frequently Asked Questions About ${projectName} `}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}

View File

@ -27,7 +27,7 @@ import ContactFormSection from '../../components/WebPageComponents/ContactFormCo
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -125,10 +125,10 @@ export default function WebSite() {
content={`Discover our CRM app tailored for the law industry, connecting departments like sales, customer service, and marketing. Streamline your operations and track leads efficiently.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Law professionals collaborating efficiently']}
mainText={`Revolutionize Your Legal Operations Today`}
subTitle={`Experience seamless integration with ${projectName}, the CRM designed for the law industry. Connect departments, track leads, and organize effortlessly.`}
@ -137,9 +137,9 @@ export default function WebSite() {
/>
<FeaturesSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Dashboard showcasing CRM features']}
withBg={1}
withBg={0}
features={features_points}
mainText={`Discover Key Features of ${projectName}`}
subTitle={`Unlock the full potential of your legal operations with ${projectName}. Streamline processes, enhance collaboration, and drive efficiency.`}
@ -147,7 +147,7 @@ export default function WebSite() {
/>
<AboutUsSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Team collaborating in modern office']}
mainText={`Empowering Legal Teams with ${projectName}`}
subTitle={`At ${projectName}, we are dedicated to transforming the way legal professionals work. Our CRM is designed to connect departments, streamline operations, and enhance productivity across the board.`}
@ -156,21 +156,21 @@ export default function WebSite() {
/>
<TestimonialsSection
projectName={'Test555'}
projectName={'Test 444'}
design={TestimonialsDesigns.MULTI_CARD_DISPLAY || ''}
testimonials={testimonials}
mainText={`What Our Clients Say About ${projectName} `}
/>
<ContactFormSection
projectName={'Test555'}
projectName={'Test 444'}
design={ContactFormDesigns.WITH_IMAGE || ''}
image={['Person typing on a laptop']}
mainText={`Get in Touch with ${projectName} `}
subTitle={`Reach out to us anytime. Our team is ready to assist you with any inquiries or support you need. Expect a response within 24 hours.`}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}

View File

@ -24,7 +24,7 @@ import TestimonialsSection from '../../components/WebPageComponents/Testimonials
export default function WebSite() {
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const projectName = 'Test555';
const projectName = 'Test 444';
useEffect(() => {
const darkElement = document.querySelector('body .dark');
@ -122,10 +122,10 @@ export default function WebSite() {
content={`Explore the range of services offered by ${projectName}. From lead management to document collaboration, discover how we can transform your legal practice.`}
/>
</Head>
<WebSiteHeader projectName={'Test555'} pages={pages} />
<WebSiteHeader projectName={'Test 444'} pages={pages} />
<main className={`flex-grow bg-white rounded-none `}>
<HeroSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Legal professionals in a meeting']}
mainText={`Transform Your Practice with ${projectName}`}
subTitle={`Discover the comprehensive services offered by ${projectName} to streamline your legal operations. From lead management to seamless document collaboration, we have you covered.`}
@ -134,9 +134,9 @@ export default function WebSite() {
/>
<FeaturesSection
projectName={'Test555'}
projectName={'Test 444'}
image={['Icons representing various services']}
withBg={0}
withBg={1}
features={features_points}
mainText={`Explore ${projectName} Services`}
subTitle={`Unlock the full potential of your legal practice with our tailored services. Discover how ${projectName} can enhance your operations.`}
@ -144,21 +144,21 @@ export default function WebSite() {
/>
<TestimonialsSection
projectName={'Test555'}
projectName={'Test 444'}
design={TestimonialsDesigns.MULTI_CARD_DISPLAY || ''}
testimonials={testimonials}
mainText={`Client Success Stories with ${projectName} `}
/>
<ContactFormSection
projectName={'Test555'}
projectName={'Test 444'}
design={ContactFormDesigns.HIGHLIGHTED_DIVERSITY || ''}
image={['Person typing on a laptop']}
mainText={`Reach Out to ${projectName} `}
subTitle={`We're here to assist you. Contact us anytime, and our team will respond within 24 hours to address your inquiries.`}
/>
</main>
<WebSiteFooter projectName={'Test555'} pages={pages} />
<WebSiteFooter projectName={'Test 444'} pages={pages} />
</div>
);
}