diff --git a/.bolt/config.json b/.bolt/config.json deleted file mode 100644 index 6b6787d..0000000 --- a/.bolt/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "template": "bolt-vite-react-ts" -} diff --git a/.bolt/prompt b/.bolt/prompt deleted file mode 100644 index d0c0a8f..0000000 --- a/.bolt/prompt +++ /dev/null @@ -1,8 +0,0 @@ -For all designs I ask you to make, have them be beautiful, not cookie cutter. Make webpages that are fully featured and worthy for production. - -By default, this template supports JSX syntax with Tailwind CSS classes, React hooks, and Lucide React for icons. Do not install other packages for UI themes, icons, etc unless absolutely necessary or I request them. - -Use icons from lucide-react for logos. - -Use stock photos from unsplash where appropriate, only valid URLs you know exist. Do not download the images, only link to them in image tags. - diff --git a/.gitignore b/.gitignore index a547bf3..db0b720 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ + # Logs logs *.log @@ -8,10 +9,11 @@ pnpm-debug.log* lerna-debug.log* node_modules -dist -dist-ssr -*.local +dev-dist +*.local +release +config.php # Editor directories and files .vscode/* !.vscode/extensions.json @@ -22,3 +24,4 @@ dist-ssr *.njsproj *.sln *.sw? + \ No newline at end of file diff --git a/.prettier b/.prettier new file mode 100644 index 0000000..3fa6037 --- /dev/null +++ b/.prettier @@ -0,0 +1,5 @@ + +{ + "tabWidth": 2, + "useTabs": false +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/add-types.ps1 b/add-types.ps1 new file mode 100644 index 0000000..bf7b859 --- /dev/null +++ b/add-types.ps1 @@ -0,0 +1,218 @@ +$typesContent = @' +export type PlatformType = "ANDROID" | "IOS"; + +export interface ComponentNode { + id: string; + name: string; + type: string; + icon?: string; + order?: number; + props: ComponentProps; + children?: ComponentNode[]; + pageId?: { + id: string; + name: string; + }; +} + +export interface ComponentProps { + identifier: string; + developer_notes?: string; + api?: string; + state?: string; + api_action?: string; + className?: string; + dataVariable?: string; +} + +export interface GlobalState { + leftPanel: ComponentNode[]; + middlePanel: ComponentNode[]; + rightPanel: ComponentNode | null; + selectedComponent: number; + rightComponentId: string; + selectedPageComponent: string; + copiedComponent: ComponentNode | null; + copiedPage: ComponentNode[]; + selectedPageId: SelectedPageId; + disabledComponent: boolean; +} + +export interface SelectedPageId { + id: string; + name: string; +} +'@ + +if (-not (Test-Path ".\src\types\global.ts")) { + New-Item -Path ".\src\types" -ItemType Directory -Force + Set-Content -Path ".\src\types\global.ts" -Value $typesContent -NoNewline +} + +$patterns = @( + # Pattern 1: Add interface for components without props + @{ + 'Match' = '(?' + 'Replace' = "interface `$1Props {}`n`nconst `$1: React.FC<`$1Props> = () =>" + }, + # Pattern 2: Add interface for components with destructured props + @{ + 'Match' = '(?' + 'Replace' = { + param($matches) + $componentName = $matches[1] + $propsText = $matches[2] + $props = $propsText -split ',\s*' | Where-Object { $_ -match '\S' } | ForEach-Object { + $prop = $_ -replace '=.*$', '' -replace '//.*$', '' -replace '\s+$', '' -replace '^\s+', '' + if ($prop -match 'children') { + " $prop: ReactNode;" + } + elseif ($prop -match 'type') { + " $prop: PlatformType;" + } + elseif ($prop -match 'dispatch') { + " $prop: React.Dispatch;" + } + elseif ($prop -match 'state') { + " $prop: GlobalState;" + } + elseif ($prop -match 'ref') { + " $prop?: React.RefObject;" + } + elseif ($prop -match 'style') { + " $prop?: React.CSSProperties;" + } + elseif ($prop -match 'className') { + " $prop?: string;" + } + elseif ($prop -match 'onClick|onSubmit|onChange|onBlur|onFocus') { + " $prop?: (event: any) => void;" + } + elseif ($prop -match 'component') { + " $prop?: ComponentNode;" + } + elseif ($prop -match 'components|leftPanel|middlePanel') { + " $prop?: ComponentNode[];" + } + elseif ($prop -match 'componentId') { + " $prop?: string;" + } + elseif ($prop -match '\[\]$') { + " $prop?: ${prop};" + } + else { + " $prop?: any;" + } + } + $propsInterface = $props -join "`n" + @" +import { PlatformType, ComponentNode, GlobalState } from '@/types/global'; + +interface ${componentName}Props { +$propsInterface +} + +const $componentName: React.FC<${componentName}Props> = ({ + $propsText +}) => +"@ + } + }, + # Pattern 3: Add React.FC type to memo wrapped components + @{ + 'Match' = 'export\s+default\s+memo\((\w+)\)' + 'Replace' = 'export default memo($1) as React.FC<$1Props>' + }, + # Pattern 4: Add return type to useEffect + @{ + 'Match' = 'useEffect\(\(\)\s*=>' + 'Replace' = 'useEffect((): void =>' + }, + # Pattern 5: Add type for state variables + @{ + 'Match' = 'useState\(([^)]+)\)' + 'Replace' = { + param($matches) + $initialValue = $matches[1].Trim() + if ($initialValue -match '^\[\s*\]\s*$') { + 'useState([])' + } + elseif ($initialValue -match '^\{\s*\}\s*$') { + 'useState>({})' + } + elseif ($initialValue -match '^".*"$') { + 'useState(' + $initialValue + ')' + } + elseif ($initialValue -match '^\d+(\.\d+)?$') { + 'useState(' + $initialValue + ')' + } + elseif ($initialValue -match '^(true|false)$') { + 'useState(' + $initialValue + ')' + } + elseif ($initialValue -match '^null$') { + 'useState(null)' + } + elseif ($initialValue -match '^undefined$') { + 'useState(undefined)' + } + else { + 'useState(' + $initialValue + ')' + } + } + } +) + +$srcPath = ".\src" +$files = Get-ChildItem -Path $srcPath -Recurse -Include "*.tsx" + +foreach ($file in $files) { + $content = Get-Content $file.FullName -Raw + $modified = $false + + # Add necessary React imports if not present + $reactImports = @() + + if (-not ($content -match '\bFC\b')) { + $reactImports += "FC" + } + if (-not ($content -match '\bReactNode\b')) { + $reactImports += "ReactNode" + } + if (-not ($content -match '\bCSSProperties\b') -and $content -match 'style\s*[?:]') { + $reactImports += "CSSProperties" + } + + if ($reactImports.Count -gt 0) { + if ($content -match 'import\s+React,\s*{([^}]*?)}\s+from\s+[''"]react[''"]') { + $existingImports = $matches[1] + $newImports = ($reactImports | Where-Object { $existingImports -notmatch "\b$_\b" }) -join ", " + if ($newImports) { + $content = $content -replace 'import\s+React,\s*{([^}]*?)}\s+from\s+[''"]react[''"]', "import React, { `$1, $newImports } from 'react'" + $modified = $true + } + } + elseif ($content -match 'import\s+React\s+from\s+[''"]react[''"]') { + $content = $content -replace 'import\s+React\s+from\s+[''"]react[''"]', "import React, { $($reactImports -join ', ') } from 'react'" + $modified = $true + } + } + + foreach ($pattern in $patterns) { + if ($content -match $pattern.Match) { + if ($pattern.Replace -is [scriptblock]) { + $content = [regex]::Replace($content, $pattern.Match, $pattern.Replace) + } + else { + $content = $content -replace $pattern.Match, $pattern.Replace + } + $modified = $true + } + } + + if ($modified) { + Write-Host "Adding types to: $($file.FullName)" + $content | Set-Content $file.FullName -NoNewline + } +} + +Write-Host "Done adding types to components and pages." diff --git a/config b/config new file mode 100644 index 0000000..9ef2e6d --- /dev/null +++ b/config @@ -0,0 +1,26 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true +[remote "origin"] + url = http://23.29.118.76:3000/mkdlabs/baas_wireframe.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master + vscode-merge-base = origin/master +[branch "wireframe"] + vscode-merge-base = master +[remote "origin2"] + url = https://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@github.com/manaknightdev/baas_wireframe.git/ + fetch = +refs/heads/*:refs/remotes/origin2/* +[branch "revert"] + vscode-merge-base = origin/master +[branch "pws"] + vscode-merge-base = origin/master +[remote "git-origin"] + url = https://github.com/mytechpassport/wireframetool.git + fetch = +refs/heads/*:refs/remotes/git-origin/* diff --git a/deploy.sh b/deploy.sh deleted file mode 100644 index 9b7eccd..0000000 --- a/deploy.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash - -# Exit on any error -set -e - -echo "🚀 Starting deployment process..." - -# Configuration -DEPLOY_PATH="/var/www/wireframev5.manaknightdigital.com" -NGINX_CONFIG="/etc/nginx/sites-available/wireframev5.manaknightdigital.com" - -# Build the application -echo "📦 Building application..." -npm install -npm run build - -# Ensure deploy directory exists -echo "📁 Setting up deployment directory..." -sudo mkdir -p $DEPLOY_PATH - -# Copy build files to deployment directory -echo "📋 Copying files to deployment directory..." -sudo cp -r dist/* $DEPLOY_PATH/ - -# Set proper permissions -echo "🔒 Setting permissions..." -sudo chown -R www-data:www-data $DEPLOY_PATH -sudo chmod -R 755 $DEPLOY_PATH - -# Create Nginx configuration if it doesn't exist -if [ ! -f "$NGINX_CONFIG" ]; then - echo "📝 Creating Nginx configuration..." - sudo tee $NGINX_CONFIG > /dev/null < { + if (value != "") { + return value; + } else { + return undefined; + } +}; + +const commandConfigMap = { + init: { + requireArgument: false, + requirements: { + arguments: [], + message: "", + }, + action() { + return [null, "git init"]; + }, + }, + branch: { + requireArgument: true, + requirements: { + arguments: ["branch name"], + message: "branch= \n eg. branch=pws", + }, + action(value) { + return [null, `git branch ${value}`]; + }, + }, + checkout: { + requireArgument: true, + requirements: { + arguments: ["branch name"], + message: "checkout= \n eg. checkout=pws", + }, + action(value) { + return [null, `git checkout ${value}`]; + }, + }, + merge: { + requireArgument: true, + requirements: { + arguments: ["branch name"], + message: "merge= \n eg. merge=pws", + }, + action(value) { + return [null, `git merge ${value}`]; + }, + }, + "add-remote": { + requireArgument: true, + requirements: { + arguments: ["remote name", "remote url"], + message: + 'add-remote= \n eg. add-remote="remotename https://github.com/username/reponame.git"', + }, + action(remoteName, remoteUrl) { + return [null, `git remote add ${remoteName} ${remoteUrl}`]; + }, + }, + "rm-remote": { + requireArgument: true, + requirements: { + arguments: ["remote name"], + message: "rm-remote= \n eg. rm-remote=pws", + }, + action(remoteName) { + return [null, `git remote remove ${remoteName}`]; + }, + }, + add: { + requireArgument: true, + requirements: { + arguments: ["file path"], + message: "add= \n eg. add=.", + }, + action(filePath) { + return [null, `git add ${filePath}`]; + }, + }, + commit: { + requireArgument: true, + requirements: { + arguments: ["commit message"], + message: 'commit= \n eg. commit="commit message"', + }, + action(commitMessage) { + return [null, `git commit -m "${commitMessage}"`]; + }, + }, + pull: { + requireArgument: false, + requirements: { + arguments: ["remote name", "branch name"], + message: 'pull= \n eg. pull="origin main"', + }, + action(remoteName = null, branchName = null) { + if (getNonNullValue(remoteName) && !getNonNullValue(branchName)) { + return [`${this.requirements.message} : branch name is missing`, null]; + } + if (!getNonNullValue(remoteName) && getNonNullValue(branchName)) { + return [`${this.requirements.message} : remote name is missing`, null]; + } + + return [ + null, + `git pull ${remoteName ? `${remoteName}` : ""} ${ + branchName ? `${branchName}` : "" + }`, + ]; + }, + }, + push: { + requireArgument: false, + requirements: { + arguments: ["remote name", "branch name"], + message: 'push= \n eg. push="origin main"', + }, + action(remoteName = null, branchName = null) { + if (getNonNullValue(remoteName) && !getNonNullValue(branchName)) { + return [`${this.requirements.message} : branch name is missing`, null]; + } + if (!getNonNullValue(remoteName) && getNonNullValue(branchName)) { + return [`${this.requirements.message} : remote name is missing`, null]; + } + + return [ + null, + `git push ${remoteName ? `${remoteName}` : ""} ${ + branchName ? `${branchName}` : "" + }`, + ]; + }, + }, +}; +// const allowedCommands = [ +// "init", +// "branch", +// "checkout", +// "add-remote", +// "rm-remote", +// "add", +// "commit", +// "pull", +// "push", +// ]; + +const computeCommand = (commandConfig, values) => { + const arguments = + commandConfig?.requirements?.arguments?.length > 1 + ? values + : [values?.join(" ")]; + + const [error, command] = commandConfig?.action(...arguments); + if (error) { + return [error, null]; + } + return [null, command]; +}; + +const runCommands = (commands, i) => { + return new Promise((resolve, reject) => { + return commandProcess(commands, i, resolve, reject); + }); +}; + +const commandProcess = (commands, i, resolve, reject) => { + if (i >= commands.length) { + return resolve([null, "All commands executed successfully"]); + } + + const command = commands[i]; + exec(command, (error, stdout, stderr) => { + console.log(`\n$Git >> ${command}`); + if (!error) { + console.log(`$Git >> ${command} command output: ${stdout}`); + commandProcess(commands, i + 1, resolve, reject); + } else { + console.error(`$Git >> Error executing Git command: ${stderr}`); + } + }); +}; + +const argvs = process.argv.splice(2); + +const startGitProcess = async () => { + return new Promise(async (resolve, reject) => { + let commands = []; + + for (const commandEntry of argvs) { + const [key, value] = commandEntry.split("="); + const commandConfig = commandConfigMap[key]; + const values = value?.trim()?.replace(/\s+/g, " ")?.split(" "); + // console.log("values >>", values); + if (!commandConfig) { + return reject(`Command ${key} is not recognised as internal command`); + } + + if (commandConfig.requireArgument) { + if (!value) { + return reject( + `Argument is required: ${commandConfig.requirements.message}` + ); + } + + if (commandConfig.requirements.arguments.length > 1) { + if (values.length !== commandConfig.requirements.arguments.length) { + return reject( + `Invalid number of arguments: ${commandConfig.requirements.message}` + ); + } + } + } + const [error, command] = computeCommand(commandConfig, values); + if (error) { + return reject(error); + } + commands = commands.concat(command); + } + + // console.log("$Git >> commands:", commands); + if (!commands?.length) { + return reject("No command to execute"); + } + + const [error, message] = await runCommands(commands, 0); + if (error) { + return reject(error); + } + return resolve(message); + }); +}; + +const main = async () => { + try { + const result = await startGitProcess(); + console.log("\n$Git >>", result); + } catch (error) { + console.error("\n$Git >> Error:", error); + } +}; + +main(); + +// git checkout master && git pull origin master && yarn build && git add . && git commit -m "Build Master" && git push origin master && git checkout wireframe && git merge master && git push origin wireframe +// const operations = argvs.map((argv) => argv.split("=")[0]?.toLowerCase()) +// const allowedCommands = Object.keys(commandConfigMap); + +// const commandValidation = operations.map((command) => { +// if (!allowedCommands.includes(command.trim())) { +// return { +// command, +// isValid: false, +// }; +// } + +// return { +// command, +// isValid: true, +// }; +// }); + +// const invalidCommands = commandValidation.filter((command) => !command.isValid); + +// if (invalidCommands.length) { +// const errorMessage = invalidCommands +// .map((command) => `${command.command} is not recognised as internal command`) +// .join(", "); + +// return [errorMessage, null]; +// } +// "commit:script": "node git-script add=. commit="Update" push="origin pws" checkout=master merge=pws push="origin master" checkout=pws" diff --git a/index.html b/index.html index f3442b7..80bda1e 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,43 @@ + - - - Wireframe V5 + + + Wireframe Tool | Manaknight Digital + + + + + - +
- + + + diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..3a19767 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,16 @@ + { + "compilerOptions": { + "jsx": "react", + "baseUrl": ".", + "paths": { + "Components/*": ["src/components/*"], + "Pages/*": ["src/pages/*"], + "Utils/*": ["src/utils/*"], + "Assets/*": ["src/assets/*"], + "Context/*": ["src/context/*"], + "Routes/*": ["src/routes/*"], + "Hooks/*": ["src/hooks/*"], + "Src/*": ["src/*"] + } + } +} diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..ce136e8 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,4 @@ +[[redirects]] + from = "/*" + to = "/" + status = 200 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index d9c37e5..0000000 --- a/package-lock.json +++ /dev/null @@ -1,4051 +0,0 @@ -{ - "name": "vite-react-typescript-starter", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vite-react-typescript-starter", - "version": "0.0.0", - "dependencies": { - "lucide-react": "^0.344.0", - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.9.1", - "@types/react": "^18.3.5", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "autoprefixer": "^10.4.18", - "eslint": "^9.9.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.11", - "globals": "^15.9.0", - "postcss": "^8.4.35", - "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", - "typescript-eslint": "^8.3.0", - "vite": "^5.4.2" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.25.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", - "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", - "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", - "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz", - "integrity": "sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz", - "integrity": "sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", - "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", - "dev": true, - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", - "dev": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", - "dev": true, - "dependencies": { - "@humanfs/core": "^0.19.0", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", - "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", - "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", - "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", - "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", - "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", - "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", - "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", - "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", - "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", - "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", - "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", - "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", - "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", - "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", - "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.11", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", - "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", - "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/type-utils": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", - "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", - "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", - "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", - "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", - "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", - "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", - "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.1", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz", - "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.5.33", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz", - "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.1.0-rc-fb9a90fa48-20240614", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz", - "integrity": "sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz", - "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==", - "dev": true, - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "0.344.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.344.0.tgz", - "integrity": "sha512-6YyBnn91GB45VuVT96bYCOKElbJzUHqp65vX8cDcu55MQL9T969v4dhGClpljamuI/+KMO9P6w9Acq1CVQGvIQ==", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", - "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.0", - "@rollup/rollup-android-arm64": "4.24.0", - "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.24.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm-musleabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", - "@rollup/rollup-linux-arm64-musl": "4.24.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", - "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-s390x-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-musl": "4.24.0", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", - "@rollup/rollup-win32-ia32-msvc": "4.24.0", - "@rollup/rollup-win32-x64-msvc": "4.24.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", - "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", - "dev": true, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.0", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz", - "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.8.1", - "@typescript-eslint/parser": "8.8.1", - "@typescript-eslint/utils": "8.8.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/vite": { - "version": "5.4.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", - "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json index feb68fd..a41af78 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,147 @@ { - "name": "vite-react-typescript-starter", + "name": "adminportal", "private": true, "version": "0.0.0", - "type": "module", "scripts": { "dev": "vite", - "build": "vite build", - "lint": "eslint .", - "preview": "vite preview" + "preinstall": "npm install --force", + "tw": "npx tailwindcss -i ./src/index.css -o ./src/output.css --watch", + "build": "tsc && vite build", + "typecheck": "tsc --noEmit", + "preview": "vite preview", + "generate-pwa-assets": "pwa-assets-generator --preset minimal public/mkd_logo.png", + "commit": "git add . && git commit -m \"Update | test fixes\" && git pull && git push origin android", + "push": "yarn build && yarn commit:script", + "commit:script": "node git-script add,commit,pull,push message=\"UPDATE | merge wireframe \" origin=master" }, "dependencies": { - "lucide-react": "^0.344.0", - "react": "^18.3.1", - "react-dom": "^18.3.1" + "@craftjs/core": "^0.2.0-beta.11", + "@fontsource/inter": "^5.0.15", + "@fontsource/roboto-mono": "^5.0.16", + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-brands-svg-icons": "^6.4.0", + "@fortawesome/free-regular-svg-icons": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@fullcalendar/core": "^5.11.3", + "@fullcalendar/daygrid": "^5.11.3", + "@fullcalendar/interaction": "^5.11.3", + "@fullcalendar/list": "^5.11.3", + "@fullcalendar/react": "^5.11.2", + "@fullcalendar/timegrid": "^5.11.3", + "@headlessui/react": "^1.7.14", + "@heroicons/react": "^2.0.18", + "@hookform/resolvers": "^3.1.0", + "@hotjar/browser": "^1.0.9", + "@mantine/core": "^6.0.19", + "@mantine/hooks": "^6.0.19", + "@react-google-maps/api": "^2.19.2", + "@stripe/react-stripe-js": "^2.1.0", + "@stripe/stripe-js": "^1.52.1", + "@tailwindcss/forms": "^0.5.3", + "@tippyjs/react": "^4.2.6", + "@types/react-toggle": "^4.0.5", + "@uppy/core": "^3.7.1", + "@uppy/dashboard": "^3.4.1", + "@uppy/drag-drop": "^3.0.2", + "@uppy/facebook": "^3.1.3", + "@uppy/file-input": "^3.0.3", + "@uppy/golden-retriever": "^3.1.0", + "@uppy/google-drive": "^3.1.1", + "@uppy/image-editor": "^2.1.2", + "@uppy/instagram": "^3.1.3", + "@uppy/onedrive": "^3.1.1", + "@uppy/progress-bar": "^3.0.3", + "@uppy/react": "^3.1.2", + "@uppy/tus": "^3.4.0", + "@uppy/webcam": "^3.3.1", + "@uppy/xhr-upload": "^3.5.0", + "ace-builds": "^1.4.12", + "apexcharts": "^3.40.0", + "axios": "^1.5.0", + "bootstrap": "^5.2.3", + "codemirror": "^5.65.16", + "file-saver": "^2.0.5", + "framer-motion": "^10.16.4", + "fullcalendar": "^5.11.3", + "html-to-image": "^1.11.11", + "jszip": "^3.10.1", + "lucide-react": "^0.475.0", + "moment": "^2.29.4", + "openai": "^4.24.1", + "papaparse": "^5.4.1", + "pdfjs-dist": "^3.4.120", + "pluralize": "^8.0.0", + "pretty-rating-react": "^2.2.0", + "qr-scanner": "^1.4.2", + "qrcode": "^1.5.3", + "react": "^18.2.0", + "react-ace": "^10.1.0", + "react-addons-update": "^15.6.3", + "react-apexcharts": "^1.4.0", + "react-calendar": "^4.2.1", + "react-codemirror2": "^7.3.0", + "react-contenteditable": "^3.3.7", + "react-dnd": "^10.0.2", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.2.0", + "react-google-maps": "^9.4.5", + "react-hook-form": "^7.46.1", + "react-icons": "^4.11.0", + "react-input-emoji": "^5.4.1", + "react-loading-skeleton": "^3.3.1", + "react-modal": "^3.16.1", + "react-modern-calendar-datepicker": "^3.1.6", + "react-outside-click-handler": "^1.3.0", + "react-pdf": "^7.7.0", + "react-quill": "^2.0.0", + "react-router": "^6.15.0", + "react-router-dom": "^6.11.1", + "react-select": "^5.8.0", + "react-speech-recognition": "^3.10.0", + "react-spinners": "^0.13.8", + "react-timeago": "^7.2.0", + "react-toggle": "^4.1.3", + "react-tooltip": "^5.25.2", + "redux": "^4.2.1", + "regenerator-runtime": "^0.14.1", + "slick-carousel": "^1.8.1", + "swiper": "^9.3.1", + "tw-elements": "^1.0.0-beta2", + "twilio-video": "^2.27.0", + "uppy": "^3.20.0", + "use-debounce": "^9.0.4", + "uuid": "^9.0.1", + "xlsx": "^0.18.5", + "yup": "^1.2.0" }, "devDependencies": { - "@eslint/js": "^9.9.1", - "@types/react": "^18.3.5", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "autoprefixer": "^10.4.18", - "eslint": "^9.9.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.11", - "globals": "^15.9.0", - "postcss": "^8.4.35", - "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", - "typescript-eslint": "^8.3.0", - "vite": "^5.4.2" + "@types/node": "^22.13.1", + "@types/prettier": "^3.0.0", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@typescript-eslint/eslint-plugin": "^8.24.0", + "@typescript-eslint/parser": "^8.24.0", + "@vite-pwa/assets-generator": "^0.0.8", + "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react-refresh": "^1.3.6", + "@vitejs/plugin-react-swc": "^3.8.0", + "autoprefixer": "^10.4.14", + "eslint": "^8.40.0", + "eslint-config-react-app": "^7.0.1", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "husky": "^8.0.3", + "lint-staged": "^13.2.2", + "postcss": "^8.4.23", + "prettier": "^2.8.8", + "prettier-plugin-tailwindcss": "^0.2.8", + "tailwindcss": "^3.3.2", + "ts-node": "^10.9.2", + "typescript": "^5.7.3", + "vite": "^4.3.5", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-pwa": "^0.16.4" } } diff --git a/pg.ts b/pg.ts new file mode 100644 index 0000000..cd2abd7 --- /dev/null +++ b/pg.ts @@ -0,0 +1,28118 @@ +const androidConfig = { + name: "Manaknight", + packageName: "com.manaknight.app", + baseUrl: "https://mkdlabs.com", + projectId: "profitpro", + secret: "15p1dfbeh2pc0uypfidk8i7r5yqx13esa", + startDestination: "splash", + isGoogleLogin: false, + isAppleLogin: false, + isFacebookLogin: false, + isInappPurchase: false, + hasAuth: true, + hasToolBar: false, + navigationType: "sideBar", + extensions: [{}], + menu: [ + { + id: "980f4fc1-8121-f7cb-e291-d65140b21fa7", + title: "Home", + icon: "ic_dialog_dialer", + destination: "home", + }, + { + id: "8c7b774e-ff8a-ccbf-6881-ecb649d918fa", + title: "Proejects", + icon: "ic_menu_gallery", + destination: "projectview", + }, + { + id: "46c9db93-486f-f959-02b3-0c2e92e56b68", + title: "Cost", + icon: "ic_menu_search", + destination: "costview", + }, + { + id: "c69ef864-1d73-bde7-b972-f846f873bc07", + title: "profile", + icon: "ic_profile", + destination: "accountview", + }, + ], + appBar: [], + enums: [], + models: [], + libraries: [], + api: [ + { + id: "_createchangeorder", + name: "Create Change Order", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/change-order", + inputs: [ + { + name: "project_id", + dataType: "", + type: "path", + rules: "is_required", + }, + { + name: "data", + dataType: "String", + type: "body", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/change-order', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \nlet validation = await validateObject(\n {\n data: 'is_required',\n },\n req.body\n);\nif (validation.error) return res.status(403).json(validation);\n\n//======\n\n\n return res.status(200).json({error: false,message: Updated successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + status_code: "200 - OK", + workflows: [ + { + id: "f6a1b478-bf26-0610-22b0-b759d5851bc7", + name: "API_Route", + configurations: { + General: { + name: "Create Change Order", + description: "", + route: "/v3/api/custom/profitpro/company/change-order", + method: "POST", + id: "_createchangeorder", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "", + type: "path", + rules: "is_required", + }, + { + name: "data", + dataType: "String", + type: "body", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "831c952d-aa93-9740-8361-52a1ac573e1d", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + }, + ], + }, + { + id: "_finalizeproject", + name: "Finalize Project", + description: "Finalize project. Send estimation to client.", + method: "GET", + route: "/v3/api/custom/profitpro/company/finalize-project", + inputs: [ + { + name: "project_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Success", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.get('/v3/api/custom/profitpro/company/finalize-project', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: Success })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "3fd8ea5c-2a63-5bb8-927d-9096cfdc88be", + name: "API_Route", + configurations: { + General: { + name: "Finalize Project", + description: "Finalize project. Send estimation to client.", + route: "/v3/api/custom/profitpro/company/finalize-project", + method: "GET", + folder: "company", + id: "_finalizeproject", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "6847b10d-cae4-fd94-438a-d6c4ada3c844", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Success", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [], + }, + ], + }, + { + id: "_getprojectreview", + name: "Get Project Review", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/project-review", + inputs: [ + { + name: "project_id", + dataType: "", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "line_items": [ { "description": "Interior Wall Painting", "estimated_by": "material", "labor_hours": 20, "entries": [ "ceiling_paint": { "quantity": 20, "rate": 1 "cost": 20 } ], "labor_budget": 1250, "material_budget": 1250, "profit_overhead": 250, "labor_hours": 20 } ], "project_totals": { "total_sale_price": 1250, "total_profit_overhead": 250, "total_labor_budget": 1250, "total_material_budget": 1250, "total_labor_hours": 20 }, "draws": [ { "percentage": 25, "amount": 500, "description": "On contract signing" }, { "percentage": 25, "amount": 500, "description": "After completion of initial phase" }, { "percentage": 50, "amount": 1000, "description": "At project completion" } ], "total_cost": 2000 }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "client_details", + dataType: "String", + }, + { + name: "line_items", + dataType: "String", + }, + { + name: "project_totals", + dataType: "String", + }, + { + name: "draws", + dataType: "String", + }, + { + name: "total_cost", + dataType: "String", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/project-review\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "line_items": [ { "description": "Interior Wall Painting", "estimated_by": "material", "labor_hours": 20, "entries": [ "ceiling_paint": { "quantity": 20, "rate": 1 "cost": 20 } ], "labor_budget": 1250, "material_budget": 1250, "profit_overhead": 250, "labor_hours": 20 } ], "project_totals": { "total_sale_price": 1250, "total_profit_overhead": 250, "total_labor_budget": 1250, "total_material_budget": 1250, "total_labor_hours": 20 }, "draws": [ { "percentage": 25, "amount": 500, "description": "On contract signing" }, { "percentage": 25, "amount": 500, "description": "After completion of initial phase" }, { "percentage": 50, "amount": 1000, "description": "At project completion" } ], "total_cost": 2000 } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + client_details: "String", + line_items: "String", + project_totals: "String", + draws: "String", + total_cost: "String", + }, + status_code: "200 - OK", + workflows: [ + { + id: "4b227650-dd66-83fd-db6e-e769faafb20a", + name: "API_Route", + configurations: { + General: { + name: "Get Project Review", + description: "", + route: "/v3/api/custom/profitpro/company/project-review", + method: "GET", + id: "_getprojectreview", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "", + type: "path", + rules: "is_required", + }, + ], + }, + }, + }, + { + id: "ed4db72c-b254-d5f2-8039-d621cbac6562", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "line_items": [ { "description": "Interior Wall Painting", "estimated_by": "material", "labor_hours": 20, "entries": [ "ceiling_paint": { "quantity": 20, "rate": 1 "cost": 20 } ], "labor_budget": 1250, "material_budget": 1250, "profit_overhead": 250, "labor_hours": 20 } ], "project_totals": { "total_sale_price": 1250, "total_profit_overhead": 250, "total_labor_budget": 1250, "total_material_budget": 1250, "total_labor_hours": 20 }, "draws": [ { "percentage": 25, "amount": 500, "description": "On contract signing" }, { "percentage": 25, "amount": 500, "description": "After completion of initial phase" }, { "percentage": 50, "amount": 1000, "description": "At project completion" } ], "total_cost": 2000 }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "client_details", + dataType: "String", + }, + { + name: "line_items", + dataType: "String", + }, + { + name: "project_totals", + dataType: "String", + }, + { + name: "draws", + dataType: "String", + }, + { + name: "total_cost", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_updatedraws", + name: "Update Draws", + description: + "Only add the cstom draws, for first and last draws You can only update them.", + method: "POST", + route: "/v3/api/custom/profitpro/company/update-draws", + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + { + name: "draws", + dataType: "String", + type: "body", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Draws Updated Successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/update-draws', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: Draws Updated Successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "eb63162d-062d-1822-d0fc-c366771a61cf", + name: "API_Route", + configurations: { + General: { + name: "Update Draws", + description: + "Only add the cstom draws, for first and last draws You can only update them.", + route: "/v3/api/custom/profitpro/company/update-draws", + method: "POST", + folder: "company", + id: "_updatedraws", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + { + name: "draws", + dataType: "String", + type: "body", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "84bec010-7c1c-c54c-d27f-e6b772fa7a7b", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Draws Updated Successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [], + }, + ], + }, + { + id: "_initializedraws", + name: "Initialize Draws", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/initialize-draws", + inputs: [ + { + name: "project_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Initialized Successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.get('/v3/api/custom/profitpro/company/initialize-draws', [ ...middlewares, TokenMiddleware()] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: Initialized Successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "3a894ab8-aeb2-f8d9-20e6-ce1c70330b96", + name: "API_Route", + configurations: { + General: { + name: "Initialize Draws", + description: "", + route: "/v3/api/custom/profitpro/company/initialize-draws", + method: "GET", + folder: "company", + id: "_initializedraws", + }, + Authentication: { + protected: true, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "72a64caa-2b44-2966-c18e-4b833d3dcff7", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Initialized Successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [], + }, + ], + }, + { + id: "_addlineitem", + name: "Add Line Item", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/add-line-item", + inputs: [ + { + name: "description", + dataType: "Integer", + type: "body", + rules: "is_required", + }, + { + name: "estimated_by", + dataType: "Integer", + type: "body", + rules: "is_required", + }, + { + name: "entries", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "labor_hours", + dataType: "Double", + type: "body", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: '{"id": 1}', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "id", + dataType: "Integer", + }, + ], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/add-line-item', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \nlet validation = await validateObject(\n {\n description: 'is_required',\n estimated_by: 'is_required',\n entries: 'is_required',\n },\n req.body\n);\nif (validation.error) return res.status(403).json(validation);\n\n//======\n\n\n return res.status(200).json({error: false,message: text,model: {\"id\": 1} })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + id: "Integer", + }, + status_code: "200 - OK", + workflows: [ + { + id: "c70188d3-f5dd-fb4e-0151-11412649233c", + name: "API_Route", + configurations: { + General: { + name: "Add Line Item", + description: "", + route: "/v3/api/custom/profitpro/company/add-line-item", + method: "POST", + id: "_addlineitem", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "description", + dataType: "Integer", + type: "body", + rules: "is_required", + }, + { + name: "estimated_by", + dataType: "Integer", + type: "body", + rules: "is_required", + }, + { + name: "entries", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "labor_hours", + dataType: "Double", + type: "body", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "7de24ab5-bf80-f38b-7f29-89681a9d35da", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: '{"id": 1}', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "id", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_createnewestimation", + name: "Create New Estimation", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/create-estimation", + inputs: [ + { + name: "customer_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "{id: 1}", + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "id", + dataType: "Integer", + }, + ], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/create-estimation', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: {id: 1} })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + id: "Integer", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "e20ce2bc-d6ba-9955-7ce8-e88071b1a1d0", + name: "API_Route", + configurations: { + General: { + name: "Create New Estimation", + description: "", + route: "/v3/api/custom/profitpro/company/create-estimation", + method: "POST", + folder: "company", + id: "_createnewestimation", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "customer_id", + dataType: "", + type: "", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "3398b9eb-3a10-1487-a9a2-5f55a90e939a", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "{id: 1}", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "id", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_trackingmaterial", + name: "Tracking (Material)", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-material-details", + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "material_budget": 2000, "material_spent": 1230, "material_balance": 770, "materials": [ { "date": "2024-01-01", "amount": 1200.00 }, { "date": "2024-02-15", "amount": 1200.00 }, { "date": "2024-03-10", "amount": 1200.00 }, { "date": "2024-04-20", "amount": 1200.00 } ] }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "material_budget", + dataType: "Double", + }, + { + name: "material_spent", + dataType: "Double", + }, + { + name: "material_balance", + dataType: "Double", + }, + { + name: "materials", + dataType: "String", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-material-details\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { "material_budget": 2000, "material_spent": 1230, "material_balance": 770, "materials": [ { "date": "2024-01-01", "amount": 1200.00 }, { "date": "2024-02-15", "amount": 1200.00 }, { "date": "2024-03-10", "amount": 1200.00 }, { "date": "2024-04-20", "amount": 1200.00 } ] } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + material_budget: "Double", + material_spent: "Double", + material_balance: "Double", + materials: "String", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "74a55096-cf1c-b155-aa09-489d7dc923d7", + name: "API_Route", + configurations: { + General: { + name: "Tracking (Material)", + description: "", + route: "/v3/api/custom/profitpro/company/get-material-details", + method: "GET", + folder: "company", + id: "_trackingmaterial", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "a6d7ff9d-2ba1-ef13-b75f-2d2266ad0466", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "material_budget": 2000, "material_spent": 1230, "material_balance": 770, "materials": [ { "date": "2024-01-01", "amount": 1200.00 }, { "date": "2024-02-15", "amount": 1200.00 }, { "date": "2024-03-10", "amount": 1200.00 }, { "date": "2024-04-20", "amount": 1200.00 } ] }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "material_budget", + dataType: "Double", + }, + { + name: "material_spent", + dataType: "Double", + }, + { + name: "material_balance", + dataType: "Double", + }, + { + name: "materials", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_trackinglabour", + name: "Tracking (Labour)", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-labor-details", + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '{ "labor_budget": 2000, "labor_spent_amount": 1230, "labor_spent_percentage": 53, "remaining_budget_amount": 770, "remaining_budget_percentage": 47, "labor_costs": [ { "name": "John Smith", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Adam Silverstone", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Jonathan McMahon", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Patrick Brownstein", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Ronnie O\'Sullivan", "rate_per_hour": 30, "hours": 6, "total_cost": 180 } ] }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "labor_budget", + dataType: "Double", + }, + { + name: "labor_spent_amount", + dataType: "Double", + }, + { + name: "labor_spent_percentage", + dataType: "Double", + }, + { + name: "remaining_budget_amount", + dataType: "Double", + }, + { + name: "remaining_budget_percentage", + dataType: "Double", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-labor-details\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,list: { "labor_budget": 2000, "labor_spent_amount": 1230, "labor_spent_percentage": 53, "remaining_budget_amount": 770, "remaining_budget_percentage": 47, "labor_costs": [ { "name": "John Smith", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Adam Silverstone", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Jonathan McMahon", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Patrick Brownstein", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Ronnie O\'Sullivan", "rate_per_hour": 30, "hours": 6, "total_cost": 180 } ] } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + labor_budget: "Double", + labor_spent_amount: "Double", + labor_spent_percentage: "Double", + remaining_budget_amount: "Double", + remaining_budget_percentage: "Double", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "5ed0805b-cadb-d31b-67d0-8e9ef3866b46", + name: "API_Route", + configurations: { + General: { + name: "Tracking (Labour)", + description: "", + route: "/v3/api/custom/profitpro/company/get-labor-details", + method: "GET", + folder: "company", + id: "_trackinglabour", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + }, + }, + }, + { + id: "8c7a2ca6-8852-700f-fab4-ff44541640e8", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '{ "labor_budget": 2000, "labor_spent_amount": 1230, "labor_spent_percentage": 53, "remaining_budget_amount": 770, "remaining_budget_percentage": 47, "labor_costs": [ { "name": "John Smith", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Adam Silverstone", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Jonathan McMahon", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Patrick Brownstein", "rate_per_hour": 30, "hours": 6, "total_cost": 180 }, { "name": "Ronnie O\'Sullivan", "rate_per_hour": 30, "hours": 6, "total_cost": 180 } ] }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "labor_budget", + dataType: "Double", + }, + { + name: "labor_spent_amount", + dataType: "Double", + }, + { + name: "labor_spent_percentage", + dataType: "Double", + }, + { + name: "remaining_budget_amount", + dataType: "Double", + }, + { + name: "remaining_budget_percentage", + dataType: "Double", + }, + ], + }, + ], + }, + { + id: "_trackingdraws", + name: "Tracking (Draws)", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-draws", + inputs: [ + { + name: "status", + dataType: "String", + type: "query", + rules: "", + }, + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 2, "name": "Credit" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 3, "name": "Adjusted by Credit" } ]', + valueType: "String", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: + '{ "status_mapping": { "0": "Received", "1": "Pending", "2": "Credit", "3": "Extra Charge" } }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "amount", + dataType: "String", + }, + { + name: "status", + dataType: "", + }, + { + name: "name", + dataType: "String", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-draws\', middlewares , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,list: [ { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 2, "name": "Credit" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 3, "name": "Adjusted by Credit" } ],mapping: { "status_mapping": { "0": "Received", "1": "Pending", "2": "Credit", "3": "Extra Charge" } } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + amount: "String", + status: "", + name: "String", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "4006ae63-e2c4-54ee-44c1-9c6a1731737d", + name: "API_Route", + configurations: { + General: { + name: "Tracking (Draws)", + description: "", + route: "/v3/api/custom/profitpro/company/get-draws", + method: "GET", + folder: "company", + id: "_trackingdraws", + }, + Authentication: { + protected: false, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "status", + dataType: "String", + type: "query", + rules: "", + }, + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "831c6c1d-3d2d-5588-e80f-34b472a2fe91", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 0, "name": "Regular Draw" }, { "amount": 200.00, "status": 2, "name": "Credit" }, { "amount": 200.00, "status": 1, "name": "Additional Charge" }, { "amount": 200.00, "status": 3, "name": "Adjusted by Credit" } ]', + valueType: "String", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: + '{ "status_mapping": { "0": "Received", "1": "Pending", "2": "Credit", "3": "Extra Charge" } }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "amount", + dataType: "String", + }, + { + name: "status", + dataType: "", + }, + { + name: "name", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_getlinedetails", + name: "Get Line Details", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/line-details", + inputs: [ + { + name: "line_id", + dataType: "", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "description": "Install electrical wiring", "materials": [ { "name": "Copper Wire", "cost": 1.80, "quantity": 100, "total": 180 }, { "name": "Conduit Pipe", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Electrical Tape", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Junction Box", "cost": 1.80, "quantity": 10, "total": 18 } ], "labor_hours": 10, "labor_budget": 100, \t "material_budget": 100, \t "profit_overhead": 50, \t "sale_price": 350 }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "material_list", + dataType: "String", + }, + { + name: "labor_hours", + dataType: "Double", + }, + { + name: "labor_budget", + dataType: "Double", + }, + { + name: "material_budget", + dataType: "Double", + }, + { + name: "profit_overhead", + dataType: "String", + }, + { + name: "sale_price", + dataType: "String", + }, + { + name: "description", + dataType: "String", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/line-details\', middlewares , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { "description": "Install electrical wiring", "materials": [ { "name": "Copper Wire", "cost": 1.80, "quantity": 100, "total": 180 }, { "name": "Conduit Pipe", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Electrical Tape", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Junction Box", "cost": 1.80, "quantity": 10, "total": 18 } ], "labor_hours": 10, "labor_budget": 100, \t "material_budget": 100, \t "profit_overhead": 50, \t "sale_price": 350 } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + material_list: "String", + labor_hours: "Double", + labor_budget: "Double", + material_budget: "Double", + profit_overhead: "String", + sale_price: "String", + description: "String", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "0a7d1b12-dbd0-27de-3372-ff30d998adc5", + name: "API_Route", + configurations: { + General: { + name: "Get Line Details", + description: "", + route: "/v3/api/custom/profitpro/company/line-details", + method: "GET", + folder: "company", + id: "_getlinedetails", + }, + Authentication: { + protected: false, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "line_id", + dataType: "", + type: "path", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "d56d151c-2ab8-add6-6f44-0431714f094a", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "description": "Install electrical wiring", "materials": [ { "name": "Copper Wire", "cost": 1.80, "quantity": 100, "total": 180 }, { "name": "Conduit Pipe", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Electrical Tape", "cost": 1.80, "quantity": 10, "total": 18 }, { "name": "Junction Box", "cost": 1.80, "quantity": 10, "total": 18 } ], "labor_hours": 10, "labor_budget": 100, \t "material_budget": 100, \t "profit_overhead": 50, \t "sale_price": 350 }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "material_list", + dataType: "String", + }, + { + name: "labor_hours", + dataType: "Double", + }, + { + name: "labor_budget", + dataType: "Double", + }, + { + name: "material_budget", + dataType: "Double", + }, + { + name: "profit_overhead", + dataType: "String", + }, + { + name: "sale_price", + dataType: "String", + }, + { + name: "description", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_getsingleprojectdetails", + name: "Get Single Project Details", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-project-details", + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "project": { "name": "Project Alpha" }, "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "job_details": [ { "description": "Install electrical wiring", "cost": 100 }, { "description": "Install plumbing fixtures", "cost": 100 }, { "description": "Paint interior walls", "cost": 100 } ], "totals": { "labor_budget": 100, "material_budget": 100, "profit_overhead": 50, "total_sale_price": 350 }, "draws": [ { "percentage": 1.25, "amount": 500, "status": 1, "description": "On contract signing" }, { "percentage": 1.25, "amount": 500, "status": 2, "description": "Draw 2" }, { "percentage": 1.25, "amount": 500, "status": 3, "description": "On Completion" } ] }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "client_details", + dataType: "String", + }, + { + name: "job_details", + dataType: "String", + }, + { + name: "totals", + dataType: "String", + }, + { + name: "draws", + dataType: "String", + }, + { + name: "project_details", + dataType: "String", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-project-details\', [ ...middlewares, TokenMiddleware()] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { "project": { "name": "Project Alpha" }, "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "job_details": [ { "description": "Install electrical wiring", "cost": 100 }, { "description": "Install plumbing fixtures", "cost": 100 }, { "description": "Paint interior walls", "cost": 100 } ], "totals": { "labor_budget": 100, "material_budget": 100, "profit_overhead": 50, "total_sale_price": 350 }, "draws": [ { "percentage": 1.25, "amount": 500, "status": 1, "description": "On contract signing" }, { "percentage": 1.25, "amount": 500, "status": 2, "description": "Draw 2" }, { "percentage": 1.25, "amount": 500, "status": 3, "description": "On Completion" } ] } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + client_details: "String", + job_details: "String", + totals: "String", + draws: "String", + project_details: "String", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "56db6160-8dc1-8e8d-390c-2a6c8133c769", + name: "API_Route", + configurations: { + General: { + name: "Get Single Project Details", + description: "", + route: "/v3/api/custom/profitpro/company/get-project-details", + method: "GET", + folder: "company", + id: "_getsingleprojectdetails", + }, + Authentication: { + protected: true, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "project_id", + dataType: "Integer", + type: "path", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "d3e604f8-baa0-b173-cdb8-31a2b270953c", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "project": { "name": "Project Alpha" }, "client_details": { "name": "John Doe", "email": "client.email@domain.com", "address": "123 Main St, Cityville, Country" }, "job_details": [ { "description": "Install electrical wiring", "cost": 100 }, { "description": "Install plumbing fixtures", "cost": 100 }, { "description": "Paint interior walls", "cost": 100 } ], "totals": { "labor_budget": 100, "material_budget": 100, "profit_overhead": 50, "total_sale_price": 350 }, "draws": [ { "percentage": 1.25, "amount": 500, "status": 1, "description": "On contract signing" }, { "percentage": 1.25, "amount": 500, "status": 2, "description": "Draw 2" }, { "percentage": 1.25, "amount": 500, "status": 3, "description": "On Completion" } ] }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "client_details", + dataType: "String", + }, + { + name: "job_details", + dataType: "String", + }, + { + name: "totals", + dataType: "String", + }, + { + name: "draws", + dataType: "String", + }, + { + name: "project_details", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_finalizingonboarding", + name: "Finalizing Onboarding", + description: + "This endpoint must be called at the last stage of registration", + method: "POST", + route: "/v3/api/custom/profitpro/company/finlize-account", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Account Setup Done.", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/finlize-account', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: Account Setup Done. })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "a68a8ace-4638-04a7-afc8-66e23741b075", + name: "API_Route", + configurations: { + General: { + name: "Finalizing Onboarding", + description: + "This endpoint must be called at the last stage of registration", + route: "/v3/api/custom/profitpro/company/finlize-account", + method: "POST", + folder: "company", + id: "_finalizingonboarding", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [], + response_model: [], + }, + }, + }, + { + id: "10aa1968-85da-0835-80d9-e871f92fe78e", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Account Setup Done.", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + }, + ], + }, + { + id: "_getsquarefootlinealfootcosts", + name: "Get Square Foot/ Lineal Foot Costs", + description: + "https://baas.manaknightdigital.com/admin/edit-wireframe/221", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-costs", + inputs: [ + { + name: "type", + dataType: "String", + type: "body", + rules: "is_required", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "name": "Product A", "cost": 120.50, "profit_overhead": 30.75, "labor_cost": 50.25, "material_cost": 40.00 }, { "name": "Product B", "cost": 200.00, "profit_overhead": 45.00, "labor_cost": 80.00, "material_cost": 75.00 }, { "name": "Product C", "cost": 150.75, "profit_overhead": 35.50, "labor_cost": 60.00, "material_cost": 55.25 } ]', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "name", + dataType: "String", + }, + { + name: "cost", + dataType: "Double", + }, + { + name: "profit_overhead", + dataType: "Double", + }, + { + name: "labor_cost", + dataType: "Double", + }, + { + name: "material_cost", + dataType: "Double", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-costs\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \nlet validation = await validateObject(\n {\n type: \'is_required\',\n },\n req.body\n);\nif (validation.error) return res.status(403).json(validation);\n\n//======\n\n\n return res.status(200).json({error: false,message: text,list: [ { "name": "Product A", "cost": 120.50, "profit_overhead": 30.75, "labor_cost": 50.25, "material_cost": 40.00 }, { "name": "Product B", "cost": 200.00, "profit_overhead": 45.00, "labor_cost": 80.00, "material_cost": 75.00 }, { "name": "Product C", "cost": 150.75, "profit_overhead": 35.50, "labor_cost": 60.00, "material_cost": 55.25 } ] })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + name: "String", + cost: "Double", + profit_overhead: "Double", + labor_cost: "Double", + material_cost: "Double", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "160da796-4cca-6f64-24fd-54176a8ecc8e", + name: "API_Route", + configurations: { + General: { + name: "Get Square Foot/ Lineal Foot Costs", + description: + "https://baas.manaknightdigital.com/admin/edit-wireframe/221", + route: "/v3/api/custom/profitpro/company/get-costs", + method: "GET", + folder: "company", + id: "_getsquarefootlinealfootcosts", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "type", + dataType: "String", + type: "body", + rules: "is_required", + }, + ], + response_model: [], + }, + }, + }, + { + id: "5758cea5-9105-7a50-79d2-1dfe3ffd99de", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "name": "Product A", "cost": 120.50, "profit_overhead": 30.75, "labor_cost": 50.25, "material_cost": 40.00 }, { "name": "Product B", "cost": 200.00, "profit_overhead": 45.00, "labor_cost": 80.00, "material_cost": 75.00 }, { "name": "Product C", "cost": 150.75, "profit_overhead": 35.50, "labor_cost": 60.00, "material_cost": 55.25 } ]', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "name", + dataType: "String", + }, + { + name: "cost", + dataType: "Double", + }, + { + name: "profit_overhead", + dataType: "Double", + }, + { + name: "labor_cost", + dataType: "Double", + }, + { + name: "material_cost", + dataType: "Double", + }, + ], + }, + ], + }, + { + id: "_addlinealfootcost", + name: "Add Lineal Foot Cost", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/add-lineal-foot-cost", + inputs: [ + { + name: "name", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "cost", + dataType: "Double", + type: "body", + rules: "is_required", + }, + { + name: "labor_cost", + dataType: "Double", + type: "body", + rules: "is_required", + }, + { + name: "hidden", + dataType: "Boolean", + type: "body", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Added Successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/add-lineal-foot-cost', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \nlet validation = await validateObject(\n {\n name: 'is_required',\n cost: 'is_required',\n labor_cost: 'is_required',\n },\n req.body\n);\nif (validation.error) return res.status(403).json(validation);\n\n//======\n\n\n return res.status(200).json({error: false,message: Added Successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + status_code: "200 - OK", + workflows: [ + { + id: "684d7b38-d12a-79ff-81ee-2fa25106b691", + name: "API_Route", + configurations: { + General: { + name: "Add Lineal Foot Cost", + description: "", + route: "/v3/api/custom/profitpro/company/add-lineal-foot-cost", + method: "POST", + id: "_addlinealfootcost", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "name", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "cost", + dataType: "Double", + type: "body", + rules: "is_required", + }, + { + name: "labor_cost", + dataType: "Double", + type: "body", + rules: "is_required", + }, + { + name: "hidden", + dataType: "Boolean", + type: "body", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "3b8bce5c-7f44-4468-c772-eeb5b35f3215", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Added Successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + }, + ], + }, + { + id: "_addsquarefootcost", + name: "Add Square Foot Cost", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/add-square-foot-cost", + inputs: [ + { + name: "name", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "cost", + dataType: "", + type: "body", + rules: "is_required", + }, + { + name: "labor_cost", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "hidden", + dataType: "Boolean", + type: "body", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Successfully Added", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/add-square-foot-cost', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \nlet validation = await validateObject(\n {\n name: 'is_required',\n cost: 'is_required',\n labor_cost: 'is_required',\n },\n req.body\n);\nif (validation.error) return res.status(403).json(validation);\n\n//======\n\n\n return res.status(200).json({error: false,message: Successfully Added })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "22aecb96-7c10-01de-947d-b1b045075450", + name: "API_Route", + configurations: { + General: { + name: "Add Square Foot Cost", + description: "", + route: "/v3/api/custom/profitpro/company/add-square-foot-cost", + method: "POST", + folder: "company", + id: "_addsquarefootcost", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "name", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "cost", + dataType: "", + type: "body", + rules: "is_required", + }, + { + name: "labor_cost", + dataType: "String", + type: "body", + rules: "is_required", + }, + { + name: "hidden", + dataType: "Boolean", + type: "body", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "abb93e55-fed0-a377-8bec-8c60794ba351", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Successfully Added", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + }, + ], + }, + { + id: "_initializeuser", + name: "Initialize User", + description: + "This API needs to be called just after sign up lambda API. It'll initialize data for the user on the database.", + method: "GET", + route: "/v3/api/custom/profitpro/company/initialize-user", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "User Initialized Successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [], + logic: "", + code: "app.get('/v3/api/custom/profitpro/company/initialize-user', [ ...middlewares, TokenMiddleware({ role: \"company\" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: User Initialized Successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: {}, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "125b04c6-df2d-cc7c-eac3-782296c494a9", + name: "API_Route", + configurations: { + General: { + name: "Initialize User", + description: + "This API needs to be called just after sign up lambda API. It'll initialize data for the user on the database.", + route: "/v3/api/custom/profitpro/company/initialize-user", + method: "GET", + folder: "company", + id: "_initializeuser", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [], + response_model: [], + }, + }, + }, + { + id: "02ee9088-3906-5292-f2ff-3c9d758d4852", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "User Initialized Successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [], + }, + ], + }, + { + id: "_savedefaultsonbording", + name: "Save Defaults (Onbording)", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/onboarding-save-defaults", + inputs: [ + { + name: "default_hourly_rate", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + type: "body", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated Successfully", + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "default_hourly_rate", + dataType: "Integer", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + }, + { + name: "workers_array", + dataType: "String", + }, + ], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/onboarding-save-defaults', middlewares , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: Updated Successfully })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + default_hourly_rate: "Integer", + default_profit_overhead: "Integer", + workers_array: "String", + }, + status_code: "200 - OK", + workflows: [ + { + id: "aa7ee9e9-d7e6-09f3-7509-de68b3837a8f", + name: "API_Route", + configurations: { + General: { + name: "Save Defaults (Onbording)", + description: "", + route: + "/v3/api/custom/profitpro/company/onboarding-save-defaults", + method: "POST", + id: "_savedefaultsonbording", + }, + Authentication: { + protected: false, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "default_hourly_rate", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + type: "body", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "8d9c5209-6e32-0653-b6d7-908215bba431", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated Successfully", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [], + }, + ], + }, + { + id: "_getprojects", + name: "Get Projects ", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/get-projects", + inputs: [ + { + name: "type", + dataType: "String", + type: "query", + rules: "", + }, + { + name: "time_period", + dataType: "String", + type: "query", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "name": "Project Alpha", "start_date": "2024-01-01", "end_date": "2024-06-30", "status": 1 }, { "name": "Project Beta", "start_date": "2024-02-15", "end_date": "2024-08-15", "status": 2 }, { "name": "Project Gamma", "start_date": "2024-03-10", "end_date": "2024-09-30", "status": 3 } ]', + valueType: "String", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: + '{status: { "1": "Active", "2": "Completed", "3": "Draft", "4": "Outstanding" }}', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "name", + dataType: "String", + }, + { + name: "start_date", + dataType: "String", + }, + { + name: "end_date", + dataType: "String", + }, + { + name: "status", + dataType: "Integer", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/get-projects\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,list: [ { "name": "Project Alpha", "start_date": "2024-01-01", "end_date": "2024-06-30", "status": 1 }, { "name": "Project Beta", "start_date": "2024-02-15", "end_date": "2024-08-15", "status": 2 }, { "name": "Project Gamma", "start_date": "2024-03-10", "end_date": "2024-09-30", "status": 3 } ],mapping: {status: { "1": "Active", "2": "Completed", "3": "Draft", "4": "Outstanding" }} })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + name: "String", + start_date: "String", + end_date: "String", + status: "Integer", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "0949613e-8381-ea5f-a19b-a2ef9fc72859", + name: "API_Route", + configurations: { + General: { + name: "Get Projects ", + description: "", + route: "/v3/api/custom/profitpro/company/get-projects", + method: "GET", + folder: "company", + id: "_getprojects", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [ + { + name: "type", + dataType: "String", + type: "query", + rules: "", + }, + { + name: "time_period", + dataType: "String", + type: "query", + rules: "", + }, + ], + response_model: [], + }, + }, + }, + { + id: "ac7f7457-fd86-9425-4a04-f96b46f5927f", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: + '[ { "name": "Project Alpha", "start_date": "2024-01-01", "end_date": "2024-06-30", "status": 1 }, { "name": "Project Beta", "start_date": "2024-02-15", "end_date": "2024-08-15", "status": 2 }, { "name": "Project Gamma", "start_date": "2024-03-10", "end_date": "2024-09-30", "status": 3 } ]', + valueType: "String", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: + '{status: { "1": "Active", "2": "Completed", "3": "Draft", "4": "Outstanding" }}', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "name", + dataType: "String", + }, + { + name: "start_date", + dataType: "String", + }, + { + name: "end_date", + dataType: "String", + }, + { + name: "status", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_onboarding", + name: "Onboarding", + description: "", + method: "POST", + route: "/v3/api/custom/profitpro/company/onboarding", + inputs: [ + { + name: "default_hourly_rate", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "name", + dataType: "String", + type: "body", + rules: "", + }, + { + name: "hourly_rate", + dataType: "", + type: "", + rules: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "[{message: 'Added successfully', id: 1 }]", + valueType: "Array", + parent: "", + }, + ], + response_model: [ + { + name: "default_hourly_rate", + dataType: "Integer", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + }, + { + name: "workers_array", + dataType: "String", + }, + ], + logic: "", + code: "app.post('/v3/api/custom/profitpro/company/onboarding', middlewares , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,list: [{message: 'Added successfully', id: 1 }] })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + default_hourly_rate: "Integer", + default_profit_overhead: "Integer", + workers_array: "String", + }, + status_code: "200 - OK", + workflows: [ + { + id: "aa7ee9e9-d7e6-09f3-7509-de68b3837a8f", + name: "API_Route", + configurations: { + General: { + name: "Onboarding", + description: "", + route: "/v3/api/custom/profitpro/company/onboarding", + method: "POST", + id: "_onboarding", + }, + Authentication: { + protected: false, + authorizedRoles: [], + }, + Api_Input: { + inputs: [ + { + name: "default_hourly_rate", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + type: "body", + rules: "", + }, + { + name: "name", + dataType: "String", + type: "body", + rules: "", + }, + { + name: "hourly_rate", + dataType: "", + type: "", + rules: "", + }, + ], + }, + }, + }, + { + id: "8d9c5209-6e32-0653-b6d7-908215bba431", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "[{message: 'Added successfully', id: 1 }]", + valueType: "Array", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "default_hourly_rate", + dataType: "Integer", + }, + { + name: "default_profit_overhead", + dataType: "Integer", + }, + { + name: "workers_array", + dataType: "String", + }, + ], + }, + ], + }, + { + id: "_companyoverview", + name: "Company Overview", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/overview", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "total_profit_overhead": 1254.00, "company_health": 7.0, "total_contracts": 325, "total_ar": 325, "material_balance": 1234.50, "material_spent": 1234.50, "labor_balance": 325.00, "labor_spent": 325.00, "drafts": 0, "outstanding": 20, "active": 9, "completed": 67 }', + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "total_profit_overhead", + dataType: "Double", + }, + { + name: "company_health", + dataType: "Double", + }, + { + name: "total_contracts", + dataType: "Integer", + }, + { + name: "total_ar", + dataType: "Integer", + }, + { + name: "material_balance", + dataType: "Double", + }, + { + name: "material_spent", + dataType: "Double", + }, + { + name: "labor_balance", + dataType: "Double", + }, + { + name: "labor_spent", + dataType: "Double", + }, + { + name: "drafts", + dataType: "Integer", + }, + { + name: "outstanding", + dataType: "Integer", + }, + { + name: "active", + dataType: "Integer", + }, + { + name: "completed", + dataType: "Integer", + }, + ], + logic: "", + code: 'app.get(\'/v3/api/custom/profitpro/company/overview\', [ ...middlewares, TokenMiddleware({ role: "company" }) ] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { "total_profit_overhead": 1254.00, "company_health": 7.0, "total_contracts": 325, "total_ar": 325, "material_balance": 1234.50, "material_spent": 1234.50, "labor_balance": 325.00, "labor_spent": 325.00, "drafts": 0, "outstanding": 20, "active": 9, "completed": 67 } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ', + doc: "", + unit: "", + protected: true, + authorizedRoles: ["company"], + imports: "", + type: "custom", + group: "custom", + columns: { + total_profit_overhead: "Double", + company_health: "Double", + total_contracts: "Integer", + total_ar: "Integer", + material_balance: "Double", + material_spent: "Double", + labor_balance: "Double", + labor_spent: "Double", + drafts: "Integer", + outstanding: "Integer", + active: "Integer", + completed: "Integer", + }, + folder: "company", + status_code: "200 - OK", + workflows: [ + { + id: "8ad9c2f3-4acb-578d-cb1c-5c46641b9d01", + name: "API_Route", + configurations: { + General: { + name: "Company Overview", + description: "", + route: "/v3/api/custom/profitpro/company/overview", + method: "GET", + folder: "company", + id: "_companyoverview", + }, + Authentication: { + protected: true, + authorizedRoles: ["company"], + }, + Api_Input: { + inputs: [], + response_model: [], + }, + }, + }, + { + id: "fbf64565-1457-7cb4-d9d5-7933d955f2da", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: + '{ "total_profit_overhead": 1254.00, "company_health": 7.0, "total_contracts": 325, "total_ar": 325, "material_balance": 1234.50, "material_spent": 1234.50, "labor_balance": 325.00, "labor_spent": 325.00, "drafts": 0, "outstanding": 20, "active": 9, "completed": 67 }', + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "total_profit_overhead", + dataType: "Double", + }, + { + name: "company_health", + dataType: "Double", + }, + { + name: "total_contracts", + dataType: "Integer", + }, + { + name: "total_ar", + dataType: "Integer", + }, + { + name: "material_balance", + dataType: "Double", + }, + { + name: "material_spent", + dataType: "Double", + }, + { + name: "labor_balance", + dataType: "Double", + }, + { + name: "labor_spent", + dataType: "Double", + }, + { + name: "drafts", + dataType: "Integer", + }, + { + name: "outstanding", + dataType: "Integer", + }, + { + name: "active", + dataType: "Integer", + }, + { + name: "completed", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_companydetailspage30", + name: "Company Details", + description: "", + method: "GET", + route: "/v3/api/custom/profitpro/company/details", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "[{sale_price: 56,remaining: 1000}]", + valueType: "String", + parent: "", + }, + ], + response_model: [ + { + name: "sale_price", + dataType: "", + }, + { + name: "remaining", + dataType: "Integer", + }, + ], + logic: "", + code: "app.get('/v3/api/custom/profitpro/company/details', middlewares , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,list: [{sale_price: 56,remaining: 1000}] })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + sale_price: "", + remaining: "Integer", + }, + status_code: "200 - OK", + workflows: [ + { + id: "ae22fce8-bdf0-5553-d11c-a8d63a04ab62", + name: "API_Route", + configurations: { + General: { + name: "Company Details", + description: "", + route: "/v3/api/custom/profitpro/company/details", + method: "GET", + id: "_companydetailspage30", + }, + Authentication: { + protected: false, + authorizedRoles: [], + }, + Api_Input: { + inputs: [], + }, + }, + }, + { + id: "e322617b-0d00-424b-d349-624aa4fe97cd", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "[{sale_price: 56,remaining: 1000}]", + valueType: "String", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "sale_price", + dataType: "", + }, + { + name: "remaining", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_getprojectstats", + name: "get project stats", + description: "", + method: "GET", + route: "/v3/api/profitpro/dashboard/project-stats", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "{ draft: 20, active: 10, completed: 10, estimate: 10 }", + valueType: "Object", + parent: "", + }, + ], + response_model: [ + { + name: "draft", + dataType: "Integer", + }, + { + name: "active", + dataType: "Integer", + }, + { + name: "completed", + dataType: "Integer", + }, + { + name: "estimate", + dataType: "Integer", + }, + ], + logic: "", + code: "app.get('/v3/api/profitpro/dashboard/project-stats', [ ...middlewares, TokenMiddleware()] , async (req, res) => { \n const sdk = req.sdk;\n sdk.setProjectId(req.projectId)\n try{\n \n\n\n return res.status(200).json({error: false,message: text,model: { draft: 20, active: 10, completed: 10, estimate: 10 } })\n } catch (err) {\n console.error(err);\n res.status(403).json({\n error: true,\n message: err.message\n });\n }\n })\n \n ", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "custom", + group: "custom", + columns: { + draft: "Integer", + active: "Integer", + completed: "Integer", + estimate: "Integer", + }, + status_code: "200 - OK", + workflows: [ + { + id: "bc99a027-7066-2956-7f60-509e9ab09825", + name: "API_Route", + configurations: { + General: { + name: "get project stats", + description: "", + route: "/v3/api/profitpro/dashboard/project-stats", + method: "GET", + id: "_getprojectstats", + }, + Authentication: { + protected: true, + authorizedRoles: [], + }, + Api_Input: { + inputs: [], + response_model: [], + }, + }, + }, + { + id: "92cfaf7b-d937-4836-304f-0dc74f3e81d2", + name: "success_response", + status_code: "200 - OK", + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "text", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "{ draft: 20, active: 10, completed: 10, estimate: 10 }", + valueType: "Object", + parent: "", + }, + ], + columns: {}, + type: "Responses", + response_model: [ + { + name: "draft", + dataType: "Integer", + }, + { + name: "active", + dataType: "Integer", + }, + { + name: "completed", + dataType: "Integer", + }, + { + name: "estimate", + dataType: "Integer", + }, + ], + }, + ], + }, + { + id: "_checkLambda", + name: "Lambda Check", + description: "", + method: "POST", + route: "/v2/api/lambda/check", + inputs: [ + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "OK", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "check", + }, + { + id: "_twofaLogin", + name: "Two FA Login", + description: "Handles the 2FA login process", + method: "POST", + route: "/v2/api/lambda/2fa/login", + inputs: [ + { + name: "email", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "password", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "qr_code", + key: "qr_code", + value: "", + valueType: "String", + parent: "", + }, + { + id: "one_time_token", + key: "one_time_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: 60, + valueType: "Number", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaSignin", + name: "Two FA Signin", + description: "Handles the 2FA signin process", + method: "POST", + route: "/v2/api/lambda/2fa/signin", + inputs: [ + { + name: "email", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "password", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "qr_code", + key: "qr_code", + value: "", + valueType: "String", + parent: "", + }, + { + id: "access_token", + key: "access_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaAuthorize", + name: "Two FA Authorize", + description: "Authorizes the user with 2FA", + method: "POST", + route: "/v2/api/lambda/2fa/authorize", + inputs: [ + { + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "qr_code", + key: "qr_code", + value: "", + valueType: "String", + parent: "", + }, + { + id: "type", + key: "type", + value: "qr", + valueType: "String", + parent: "", + }, + { + id: "access_token", + key: "access_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaEnable", + name: "Two FA Enable", + description: "Enables 2FA for the user", + method: "POST", + route: "/v2/api/lambda/2fa/enable", + inputs: [ + { + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "token", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "qr_code", + key: "qr_code", + value: "", + valueType: "String", + parent: "", + }, + { + id: "access_token", + key: "access_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaDisable", + name: "Two FA Disable", + description: "Disables 2FA for the user", + method: "POST", + route: "/v2/api/lambda/2fa/disable", + inputs: [ + { + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaVerify", + name: "Two FA Verify", + description: "Verifies the 2FA token", + method: "POST", + route: "/v2/api/lambda/2fa/verify", + inputs: [ + { + name: "token", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "access_token", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "valid", + key: "valid", + value: "true", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Verified Successfully", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_twofaAuth", + name: "Two FA Auth", + description: "Performs 2FA authentication", + method: "POST", + route: "/v2/api/lambda/2fa/auth", + inputs: [ + { + name: "code", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "token", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "role", + key: "role", + value: "", + valueType: "String", + parent: "", + }, + { + id: "token", + key: "token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "twofa", + }, + { + id: "_analyticsLog", + name: "Analytics Log", + description: "Endpoint for logging analytics data", + method: "POST", + route: "/v2/api/lambda/analytics/", + inputs: [ + { + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "session_id", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "status", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "user_agent", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "application", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "document", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "url", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "link_clicks", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "clicked_buttons", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "client_ip", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "events", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "total_time", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "Object", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Added successfully", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_analyticsEndpoint", + name: "Get Analytics", + description: "Endpoint for getting analytics data", + method: "GET", + route: "/v2/api/lambda/analytics/data", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "user_analytics", + key: "user_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "guest_analytics", + key: "guest_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "click_analytics", + key: "click_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_heatmapAnalytics", + name: "Log Heatmap Analytics", + description: "Endpoint for logging heatmap data", + method: "POST", + route: "/v2/api/lambda/heatmap", + inputs: [ + { + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "session_id", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "user_agent", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "scroll_position", + type: "body", + rules: "required", + dataType: "Object", + }, + { + name: "coordinates", + type: "body", + rules: "required", + dataType: "Object", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "client_ip", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "screen_size", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "screen_width", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "page", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "screen_height", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "snapshot", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "total_time", + type: "body", + rules: "", + dataType: "Number", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "Object", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Added successfully", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_heatmapDataEndpoint", + name: "Get Heatmap Data ", + description: "Endpoint for retrieving heatmap data", + method: "GET", + route: "/v2/api/lambda/heatmap/data", + inputs: [ + { + name: "custom_date", + type: "query", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: "false", + valueType: "Object", + parent: "", + }, + { + id: "user_analytics", + key: "user_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "guest_analytics", + key: "guest_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "heat_map_data", + key: "heat_map_data", + value: "", + valueType: "Array", + parent: "model", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_userSessionsDataEndpoint", + name: "User Sessions Data", + description: "Endpoint for retrieving user session data", + method: "GET", + route: "/v2/api/lambda/user-sessions/data", + inputs: [ + { + name: "custom_date", + type: "query", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: "false", + valueType: "Object", + parent: "", + }, + { + id: "user_analytics", + key: "user_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "guest_analytics", + key: "guest_analytics", + value: "", + valueType: "Object", + parent: "model", + }, + { + id: "heat_map_data", + key: "heat_map_data", + value: "", + valueType: "Array", + parent: "model", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_userSessionsAnalytics", + name: "Create User Sessions Analytics", + description: "Endpoint for creating user sessions analytics", + method: "POST", + route: "/v2/api/lambda/analytics/user-sessions/", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer", + }, + { + name: "session_id", + type: "body", + rules: "", + dataType: "Integer", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "events", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "screen_width", + type: "body", + rules: "", + dataType: "Integer", + }, + { + name: "screen_height", + type: "body", + rules: "", + dataType: "Integer", + }, + { + name: "screen_size", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "start_time", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "end_time", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "html_copy", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "User session created successfully", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "analytics", + }, + { + id: "_appleLoginMobileEndpoint", + name: "Apple Login Mobile Endpoint", + description: "Endpoint for login via iOS app", + method: "POST", + route: "/v2/api/lambda/apple/login/mobile", + inputs: [ + { + name: "first_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "last_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "identityToken", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "apple_id", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "role", + key: "role", + value: "", + valueType: "String", + parent: "", + }, + { + id: "access_token", + key: "access_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "refresh_token", + key: "refresh_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "apple_login", + }, + { + id: "_appleLogin", + name: "Apple Login", + description: "Endpoint for Apple login", + method: "GET", + route: "/v2/api/lambda/apple/login", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: "true", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "apple_login", + }, + { + id: "_appleAuthCode", + name: "Apple Auth Code ", + description: "Endpoint for handling Apple authorization code", + method: "POST", + route: "/v2/api/lambda/apple/code", + inputs: [ + { + id: "state", + name: "state", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "code", + name: "code", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "true", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "apple_login", + }, + { + id: "_googleCode", + name: "Google Code", + method: "GET", + description: "", + route: "/v2/api/lambda/google/code", + inputs: [ + { + id: "state", + name: "state", + value: "", + datType: "String", + rules: "optional", + type: "query", + }, + ], + response: [], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "google", + }, + { + id: "_googleCodeMobile", + name: "Google Code Mobile", + method: "GET", + description: + "Default function for the mobile app Google login endpoint with code exchange.", + route: "/v2/api/lambda/google/code/mobile", + inputs: [ + { + id: "role", + name: "role", + type: "query", + rules: "optional", + dataType: "String", + value: "user", + }, + { + id: "is_refresh", + name: "is_refresh", + type: "query", + rules: "optional", + dataType: "Boolean", + value: "false", + }, + { + id: "code", + name: "code", + type: "query", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "role", + key: "role", + value: "", + valueType: "String", + parent: "", + }, + { + id: "token", + key: "token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "String", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "refrsh_token", + key: "refresh_token", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "google_login", + }, + { + id: "_googleLogin", + name: "Google Login", + method: "GET", + description: + "Default function for generating Google login URL for user registration.", + route: "/v2/api/lambda/google/login", + inputs: [ + { + id: "role", + name: "role", + type: "query", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "company_id", + name: "company_id", + type: "query", + rules: "optional", + dataType: "String", + value: "", + }, + { + id: "is_refresh", + name: "is_refresh", + type: "query", + rules: "optional", + dataType: "Boolean", + value: "", + }, + ], + response: [], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "google_login", + }, + { + id: "_blogAll", + name: "Blog All", + description: "Endpoint for retrieving all blog posts", + method: "GET", + route: "/v2/api/lambda/blog/all", + inputs: [ + { + name: "limit", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "offset", + type: "query", + rules: "", + dataType: "Integer", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Integer", + parent: "", + }, + { + id: "offset", + key: "offset", + value: "", + valueType: "Integer", + parent: "", + }, + { + id: "count", + key: "count", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogSimilar", + name: "Blog Similar", + description: "Endpoint for retrieving similar blog posts", + method: "GET", + route: "/v2/api/lambda/blog/similar/:id", + inputs: [ + { + name: "top", + type: "query", + rules: "", + dataType: "Integer", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogFilter", + name: "Blog Filter", + description: "Endpoint for filtering blog posts", + method: "GET", + route: "/v2/api/lambda/blog/filter", + inputs: [ + { + name: "categories", + type: "query", + rules: "", + dataType: "Array", + }, + { + name: "tags", + type: "query", + rules: "", + dataType: "Array", + }, + { + name: "rule", + type: "query", + rules: "", + dataType: "String", + }, + { + name: "search", + type: "query", + rules: "", + dataType: "String", + }, + { + name: "limit", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "page", + type: "query", + rules: "", + dataType: "Integer", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogCreate", + name: "Blog Create", + description: "Endpoint for creating a new blog post", + method: "POST", + route: "/v2/api/lambda/blog/create", + inputs: [ + { + name: "title", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "body", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "meta", + type: "body", + rules: "", + dataType: "Object", + }, + { + name: "tags", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "categories", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "content", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "thumbnail", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "Blog Created.", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogEdit", + name: "Blog Edit", + description: "Endpoint for editing an existing blog post", + method: "POST", + route: "/v2/api/lambda/blog/edit/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + { + name: "title", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "content", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "meta", + type: "body", + rules: "", + dataType: "Object", + }, + { + name: "tags", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "categories", + type: "body", + rules: "", + dataType: "Array", + }, + { + name: "thumbnail", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "Blog Edited.", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogDelete", + name: "Blog Delete", + description: "Endpoint for deleting an existing blog post", + method: "DELETE", + route: "/v2/api/lambda/blog/delete/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "Blog Deleted.", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogSingle", + name: "Blog Single", + description: "Endpoint for retrieving a single blog post", + method: "GET", + route: "/v2/api/lambda/blog/single/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "data_id", + key: "data__id", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_title", + key: "data__title", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_description", + key: "data__description", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_content", + key: "data__content", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_thumbnail", + key: "data__thumbnail", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_author", + key: "data__author", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_meta", + key: "data__meta", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_create_at", + key: "data__create_at", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_update_at", + key: "data__update_at", + value: "", + valueType: "String", + parent: "data", + }, + { + id: "data_tags", + key: "data__tags", + value: "", + valueType: "Array", + parent: "data", + }, + { + id: "data_tags_name", + key: "data__tags_name", + value: "", + valueType: "String", + parent: "data_tags", + }, + { + id: "data_tags_id", + key: "data_tags__id", + value: "", + valueType: "String", + parent: "data_tags", + }, + { + id: "data_categories", + key: "data__categories", + value: "", + valueType: "Array", + parent: "data", + }, + { + id: "data_categories_name", + key: "data_categories__name", + value: "", + valueType: "String", + parent: "data_categories", + }, + { + id: "data_categories_id", + key: "data_categories__id", + value: "", + valueType: "String", + parent: "data_categories", + }, + { + id: "data_views", + key: "data__views", + value: 0, + valueType: "Number", + parent: "data", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogTags", + name: "Blog Tags", + description: + "Endpoint for retrieving a blog tag or creating if it does not exist ", + method: "POST", + route: "/v2/api/lambda/blog/tags", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "tag_id", + key: "tag_id", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogTagsUpdate", + name: "Blog Tags Update", + description: "Endpoint for updating a blog tag by ID", + method: "POST", + route: "/v2/api/lambda/blog/tags/:id", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated!", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogTagsRetrieve", + name: "Blog Tags Retrieve", + description: "Endpoint for retrieving blog tags", + method: "GET", + route: "/v2/api/lambda/blog/tags", + inputs: [ + { + name: "limit", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "page", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "name", + type: "query", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: [], + valueType: "Array", + parent: "", + }, + { + id: "limit", + key: "limit", + value: 10, + valueType: "Integer", + parent: "", + }, + { + id: "page", + key: "page", + value: 1, + valueType: "Integer", + parent: "", + }, + { + id: "total", + key: "total", + value: 0, + valueType: "Integer", + parent: "", + }, + { + id: "num_pages", + key: "num_pages", + value: 0, + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogTagsDelete", + name: "Blog Tags Delete by ID", + description: "Endpoint for deleting a blog tag by ID", + method: "DELETE", + route: "/v2/api/lambda/blog/tags/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Tag Deleted", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: ["admin"], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogCategoryCreate", + name: "Create Blog Category", + description: "Endpoint for creating a new blog category", + method: "POST", + route: "/v2/api/lambda/blog/category", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "parent_id", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogCategoryUpdate", + name: "Update Blog Category", + description: "Endpoint for updating a blog category", + method: "POST", + route: "/v2/api/lambda/blog/category/:id", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "parent_id", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: false, + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "Updated", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogCategoryGet", + name: "Get Blog Category", + description: "Endpoint for retrieving blog categories", + method: "GET", + route: "/v2/api/lambda/blog/category", + inputs: [ + { + name: "limit", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "page", + type: "query", + rules: "", + dataType: "Integer", + }, + { + name: "name", + type: "query", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Integer", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Integer", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Integer", + parent: "", + }, + { + id: "num_pages", + key: "num_pages", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogSubcategoryGet", + name: "Get Blog Subcategory", + description: "Endpoint for retrieving subcategories of a blog category", + method: "GET", + route: "/v2/api/lambda/blog/subcategory/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_blogDeleteCategory", + name: "Delete Blog Category", + description: "Endpoint for deleting a blog category", + method: "DELETE", + route: "/v2/api/lambda/blog/category/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "data", + key: "data", + value: "Deleted", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "blog", + }, + { + id: "_captchaTest", + name: "Captcha Test", + description: "Endpoint for generating a captcha test", + method: "GET", + route: "/v2/api/lambda/test/:width?/:height?/", + inputs: [ + { + name: "width", + type: "path", + rules: "", + dataType: "Integer", + }, + { + name: "height", + type: "path", + rules: "", + dataType: "Integer", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: '', + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "captcha", + }, + { + id: "_captchaGenerate", + name: "Captcha Generate", + description: "Endpoint for generating a captcha", + method: "GET", + route: "/v2/api/lambda/captcha/:width?/:height?/", + inputs: [ + { + name: "width", + type: "path", + rules: "", + dataType: "Integer", + }, + { + name: "height", + type: "path", + rules: "", + dataType: "Integer", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "image", + key: "image", + value: "", + valueType: "String", + parent: "model", + }, + { + id: "text", + key: "text", + value: "", + valueType: "String", + parent: "model", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "captcha", + }, + { + id: "_googleCaptchaVerify", + name: "Google Captcha Verify", + description: "Endpoint for verifying Google reCAPTCHA token", + method: "POST", + route: "/v2/api/lambda/google-captcha/", + inputs: [ + { + name: "formData", + type: "body", + rules: "", + dataType: "Object", + }, + { + name: "captchaToken", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "captcha", + }, + { + id: "_createCmsLambda", + name: "Create CMS Lambda", + method: "POST", + description: "Create new CMS record", + route: "/v2/api/lambda/cms", + inputs: [ + { + name: "page", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "key", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "type", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "value", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "insertResult", + valueType: "String", + parent: "", + }, + ], + code: 'app.post("/v2/api/lambda/cms", middlewares, async function (req, res) {\n try {\n let client = req.app.get("subscriber");\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n if (!req.body.page) {\n return res.status(403).json({\n error: true,\n message: "Page Missing",\n validation: { page: "page missing" },\n });\n }\n \n if (!req.body.key) {\n return res.status(403).json({\n error: true,\n message: "Key Missing",\n validation: { key: "key missing" },\n });\n }\n \n if (!req.body.type) {\n return res.status(403).json({\n error: true,\n message: "Type Missing",\n validation: { type: "type missing" },\n });\n }\n \n if (!req.body.value) {\n return res.status(403).json({\n error: true,\n message: "Value Missing",\n validation: { value: "value missing" },\n });\n }\n \n const insertResult = await sdk.insert({\n page: req.body.page,\n content_type: req.body.type,\n content_key: req.body.key,\n content_value: req.body.value,\n create_at: sqlDateFormat(new Date()),\n update_at: sqlDateTimeFormat(new Date()),\n });\n \n const getAllResult = await sdk.get({});\n \n client.set("cms-" + req.projectId, JSON.stringify(getAllResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n const getAllPageResult = await sdk.get({\n page: req.body.page,\n });\n \n client.set("cms-" + req.projectId + "-" + req.body.page, JSON.stringify(getAllPageResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n const getAllPageKeyResult = await sdk.get({\n page: req.body.page,\n content_key: req.body.key,\n });\n \n client.set("cms-" + req.projectId + "-" + req.body.page + "-" + req.body.key, JSON.stringify(getAllPageKeyResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n return res.status(200).json({\n error: false,\n message: insertResult,\n });\n } catch (error) {\n console.log(error);\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: + 'const TokenMiddleware = require("../../../middleware/TokenMiddleware");', + type: "default", + group: "cms", + }, + { + id: "_updateCmsLambda", + name: "Update CMS Lambda", + method: "PUT", + description: "Update a CMS record", + route: "/v2/api/lambda/cms/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "required", + dataType: "String", + }, + { + name: "page", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "key", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "type", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "value", + type: "body", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "updateResult", + valueType: "String", + parent: "", + }, + ], + code: 'app.put("/v2/api/lambda/cms/:id", middlewares, async function (req, res) {\n try {\n let client = req.app.get("subscriber");\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n if (!req.body.page) {\n return res.status(403).json({\n error: true,\n message: "Page Missing",\n validation: { page: "page missing" },\n });\n }\n \n if (!req.body.key) {\n return res.status(403).json({\n error: true,\n message: "Key Missing",\n validation: { key: "key missing" },\n });\n }\n \n if (!req.body.type) {\n return res.status(403).json({\n error: true,\n message: "Type Missing",\n validation: { type: "type missing" },\n });\n }\n \n if (!req.body.value) {\n return res.status(403).json({\n error: true,\n message: "Value Missing",\n validation: { value: "value missing" },\n });\n }\n \n const updateResult = await sdk.update(\n {\n page: req.body.page,\n content_type: req.body.type,\n content_key: req.body.key,\n content_value: req.body.value,\n update_at: sqlDateTimeFormat(new Date()),\n },\n req.params.id\n );\n \n const getAllResult = await sdk.get({});\n \n client.set("cms-" + req.projectId, JSON.stringify(getAllResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n const getAllPageResult = await sdk.get({\n page: req.body.page,\n });\n \n client.set("cms-" + req.projectId + "-" + req.body.page, JSON.stringify(getAllPageResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n const getAllPageKeyResult = await sdk.get({\n page: req.body.page,\n content_key: req.body.key,\n });\n \n client.set("cms-" + req.projectId + "-" + req.body.page + "-" + req.body.key, JSON.stringify(getAllPageKeyResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n return res.status(200).json({\n error: false,\n message: updateResult,\n });\n } catch (error) {\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_deleteCmsLambda", + name: "Delete CMS Lambda", + method: "DELETE", + description: "Delete a CMS record", + route: "/v2/api/lambda/cms/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "deleted", + valueType: "String", + parent: "", + }, + ], + code: 'app.delete("/v2/api/lambda/cms/:id", middlewares, async function (req, res) {\n try {\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n if (!req.params.id) {\n return res.status(403).json({\n error: true,\n message: "ID Missing",\n validation: { id: "id missing" },\n });\n }\n \n await sdk.delete({}, req.params.id);\n \n return res.status(200).json({\n error: false,\n message: "deleted",\n });\n } catch (error) {\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_getCmsByIdLambda", + name: "Get CMS by ID Lambda", + method: "GET", + description: "Get A CMS Record by ID", + route: "/v2/api/lambda/cms/id/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "model", + value: "result[0]", + valueType: "Object", + parent: "", + }, + ], + code: 'app.get("/v2/api/lambda/cms/id/:id", publicMiddlewares, async function (req, res) {\n try {\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n if (!req.params.id) {\n return res.status(403).json({\n error: true,\n message: "ID Missing",\n validation: { id: "id missing" },\n });\n }\n \n const result = await sdk.get({ id: req.params.id });\n \n if (result.length > 0) {\n return res.status(200).json({\n error: false,\n model: result[0],\n });\n } else {\n return res.status(200).json({\n error: false,\n model: null,\n });\n }\n } catch (error) {\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_getCmsByPageAndKeyLambda", + name: "Get CMS by Page and Key Lambda", + method: "GET", + description: "Get CMS by Page and Key", + route: "/v2/api/lambda/cms/page/:page/:key", + inputs: [ + { + name: "page", + type: "path", + rules: "required", + dataType: "String", + }, + { + name: "key", + type: "path", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + ], + code: 'app.get("/v2/api/lambda/cms/page/:page/:key", publicMiddlewares, async function (req, res) {\n try {\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n let client = req.app.get("subscriber");\n const getall = await client.get("cms-" + req.projectId + "-" + req.params.page + "-" + req.params.key);\n \n if (getall) {\n return res.status(200).send(getall);\n }\n \n const getAllResult = await sdk.get({\n page: req.params.page,\n content_key: req.params.key,\n });\n \n client.set("cms-" + req.projectId + "-" + req.params.page + "-" + req.params.key, JSON.stringify(getAllResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n return res.status(200).send(getAllResult);\n } catch (error) {\n console.log("ERROR: ", error);\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_getCmsByPageLambda", + name: "Get CMS by Page Lambda", + method: "GET", + description: "Get All CMS records for a particular page.", + route: "/v2/api/lambda/cms/page/:page", + inputs: [ + { + name: "page", + type: "path", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + ], + code: 'app.get("/v2/api/lambda/cms/page/:page", publicMiddlewares, async function (req, res) {\n try {\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n let client = req.app.get("subscriber");\n const getall = await client.get("cms-" + req.projectId + "-" + req.params.page);\n if (getall) {\n return res.status(200).send(getall);\n }\n \n const getAllResult = await sdk.get({\n page: req.params.page,\n });\n \n client.set("cms-" + req.projectId + "-" + req.params.page, JSON.stringify(getAllResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n return res.status(200).send(getAllResult);\n } catch (error) {\n console.log("ERROR: ", error);\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_getAllCmsLambda", + name: "Get All CMS Lambda", + method: "GET", + description: "Get all CMS records", + route: "/v2/api/lambda/cms/all", + inputs: [], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + ], + code: 'app.get("/v2/api/lambda/cms/all", publicMiddlewares, async function (req, res) {\n try {\n let sdk = req.sdk;\n sdk.setProjectId(req.projectId);\n sdk.setTable("cms");\n \n let client = req.app.get("subscriber");\n const getall = await client.get("cms-" + req.projectId);\n if (getall) {\n return res.status(200).send(getall);\n }\n \n const getAllResult = await sdk.get({});\n \n client.set("cms-" + req.projectId, JSON.stringify(getAllResult), "EX", 60 * 60, function (data) {\n console.log("SET", data);\n });\n \n return res.status(200).send(getAllResult);\n } catch (error) {\n console.log("ERROR: ", error);\n return res.status(403).json({\n error: true,\n message: "Something went wrong",\n });\n }\n });', + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "cms", + }, + { + id: "_registerLambda", + name: "Register Lambda", + method: "POST", + description: "", + route: "/v2/api/lambda/register", + inputs: [ + { + name: "email", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "verify", + type: "body", + rules: "", + dataType: "Boolean", + }, + { + name: "is_refresh", + type: "body", + rules: "", + dataType: "Boolean", + }, + { + name: "password", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "first_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "last_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "photo", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "role", + key: "role", + value: "req.body.role", + valueType: "String", + parent: "", + }, + { + id: "token", + key: "token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "refresh_token", + key: "refresh_token", + value: "refreshToken", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "result", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: + 'const TokenMiddleware = require("../../../middleware/TokenMiddleware");', + type: "default", + group: "register", + }, + { + id: "_loginLambda", + name: "Login Lambda", + method: "POST", + description: "", + route: "/v2/api/lambda/login", + inputs: [ + { + name: "email", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "password", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "is_refresh", + type: "body", + rules: "", + dataType: "Boolean", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "role", + key: "role", + value: "role", + valueType: "String", + parent: "", + }, + { + id: "token", + key: "token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "refresh_token", + key: "refresh_token", + value: "refreshToken", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "", + valueType: "Int", + parent: "", + }, + { + id: "first_name", + key: "first_name", + value: "", + valueType: "String", + parent: "", + }, + { + id: "last_name", + key: "last_name", + value: " ", + valueType: "String", + parent: "", + }, + { + id: "photo", + key: "photo", + value: "", + valueType: "String", + parent: "", + }, + { + id: "two_factor_enabled", + key: "two_factor_enabled", + value: "", + valueType: "Boolean", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "login", + }, + { + id: "_marketingLoginLambda", + name: "Marketing Login Lambda", + method: "POST", + description: "", + route: "/v2/api/lambda/marketing-login", + inputs: [ + { + name: "email", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "password", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "role", + type: "body", + rules: "required", + dataType: "String", + }, + { + name: "is_refresh", + type: "body", + rules: "", + dataType: "Boolean", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "role", + key: "role", + value: "role", + valueType: "String", + parent: "", + }, + { + id: "token", + key: "token", + value: + "JwtService.createAccessToken({ user_id: result.id, role }, config.jwt_expire, config.jwt_key)", + valueType: "String", + parent: "", + }, + { + id: "refresh_token", + key: "refresh_token", + value: "refreshToken", + valueType: "String", + parent: "", + }, + { + id: "expire_at", + key: "expire_at", + value: "config.jwt_expire", + valueType: "Number", + parent: "", + }, + { + id: "user_id", + key: "user_id", + value: "result.id", + valueType: "String", + parent: "", + }, + { + id: "two_factor_enabled", + key: "two_factor_enabled", + value: "result.two_factor_authentication === 1 ? true : false", + valueType: "Boolean", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "login", + }, + { + id: "_profile", + name: "profile", + method: "GET", + description: "", + route: "/v2/api/lambda/profile", + inputs: [], + response: [ + { + id: "id", + key: "id", + value: "result[0].id", + valueType: "String", + parent: "", + }, + { + id: "first_name", + key: "first_name", + value: "result[0].first_name", + valueType: "String", + parent: "", + }, + { + id: "email", + key: "email", + value: "result[0].email", + valueType: "String", + parent: "", + }, + { + id: "role", + key: "role", + value: "result[0].role", + valueType: "String", + parent: "", + }, + { + id: "last_name", + key: "last_name", + value: "result[0].last_name", + valueType: "String", + parent: "", + }, + { + id: "phone", + key: "phone", + value: 'result[0].phone ?? ""', + valueType: "String", + parent: "", + }, + { + id: "photo", + key: "photo", + value: 'result[0].photo ?? ""', + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "profile", + }, + { + id: "_profileUpdate", + name: "Profile Update", + method: "POST", + description: "", + route: "/v2/api/lambda/profile", + inputs: [ + { + name: "first_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "last_name", + type: "body", + rules: "", + dataType: "String", + }, + { + name: "photo", + type: "body", + rules: "", + dataType: "String", + defaultValue: "null", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "Updated", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "profile", + }, + { + id: "_uploadImageLocalDefault", + name: "Upload Image Local Default", + method: "POST", + description: "", + route: "/v2/api/lambda/upload", + inputs: [ + { + name: "file", + type: "multipart", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "id", + key: "id", + value: "", + valueType: "String", + parent: "", + }, + { + id: "url", + key: "url", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: + '\n const imageMiddlewares = require("../../../middleware/imageMiddlewares");\n const sizeOf = require("image-size");\n const fs = require("fs");\n const logService = require("../../../services/logService");\n const { sqlDateFormat, sqlDateTimeFormat } = require("../../../utils/dateUtils");\n ', + type: "default", + group: "upload", + }, + { + id: "_uploadImageS3", + name: "UploadImageS3", + method: "POST", + description: "", + route: "/v2/api/lambda/s3/upload", + inputs: [ + { + name: "file", + type: "multipart", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "id", + key: "id", + value: "", + valueType: "String", + parent: "", + }, + { + id: "url", + key: "url", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "upload", + }, + { + id: "_preferenceFetch", + name: "Preference Fetch", + method: "GET", + description: "", + route: "/v2/api/lambda/preference", + inputs: [], + response: [ + { + id: "user_id", + key: "user_id", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "fcm_token", + key: "fcm_token", + value: "", + valueType: "String", + parent: "", + }, + { + id: "first_name", + key: "first_name", + value: "", + valueType: "String", + parent: "", + }, + { + id: "last_name", + key: "last_name", + value: "", + valueType: "String", + parent: "", + }, + { + id: "email", + key: "email", + value: "", + valueType: "String", + parent: "", + }, + { + id: "role", + key: "role", + value: "", + valueType: "String", + parent: "", + }, + { + id: "phone", + key: "phone", + value: "", + valueType: "String", + parent: "", + }, + { + id: "photo", + key: "photo", + value: "", + valueType: "String", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "preference", + }, + { + id: "_preferenceUpdate", + name: "Preference Update", + method: "POST", + description: "", + route: "/v2/api/lambda/preference", + inputs: [ + { + name: "payload", + type: "body", + rules: "required", + dataType: "Object", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "preference", + }, + { + id: "_treeSow", + name: "Get Sow Tree", + method: "GET", + description: "", + route: "/v4/api/records/sow", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "preference", + }, + { + id: "_appAlertsList", + name: "App Alerts List", + method: "GET", + description: "", + route: "/v4/api/records/alerts", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "preference", + }, + { + id: "_appAlertsUpdate", + name: "App Alerts Update", + method: "PUT", + description: "", + route: "/v4/api/records/alerts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "required", + dataType: "String", + }, + { + name: "is_read", + type: "body", + rules: "required", + dataType: "Int", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "preference", + }, + { + id: "_ecomProductDefault", + name: "Retrieve Product Default", + method: "POST", + description: + "Default function for retrieving e-commerce products with pagination.", + route: "/v2/api/lambda/ecom/product/", + inputs: [ + { + id: "page", + name: "page", + type: "body", + rules: "required", + dataType: "Number", + value: "", + }, + { + id: "limit", + name: "limit", + type: "body", + rules: "required", + dataType: "Number", + value: "", + }, + { + id: "sortId", + name: "sortId", + type: "body", + rules: "optional", + dataType: "String", + value: "", + }, + { + id: "direction", + name: "direction", + type: "body", + rules: "optional", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "num_pages", + key: "num_pages", + value: "", + valueType: "Number", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomProductByIdDefault", + name: "Ecom Product by ID Default", + method: "GET", + description: + "Default function for retrieving a specific e-commerce product by ID or slug.", + route: "/v2/api/lambda/ecom/product/:product_identifier", + inputs: [ + { + id: "product_identifier", + name: "product_identifier", + type: "params", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "model", + key: "message", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomProductAddLambda", + name: "Add Ecom Product Lambda", + method: "POST", + description: "Create Product.", + route: "/v3/api/custom/lambda/ecom/product/add", + inputs: [ + { + id: "slug", + name: "slug", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "category_id", + name: "category_id", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "type", + name: "type", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "quantity", + name: "quantity", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "data", + name: "data", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "name", + name: "name", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "is_taxable", + name: "is_taxable", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "is_shipping", + name: "is_shipping", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "is_sticky", + name: "is_sticky", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "is_featured", + name: "is_featured", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "is_downloadable", + name: "is_downloadable", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "download_limit", + name: "download_limit", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "is_backorder", + name: "is_backorder", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "sold_single", + name: "sold_single", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "manage_stock", + name: "manage_stock", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "thumbnail_image", + name: "thumbnail_image", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "featured_image", + name: "featured_image", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + { + id: "image", + name: "image", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "sku", + name: "sku", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "weight", + name: "weight", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "height", + name: "height", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "length", + name: "length", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "weight_unit", + name: "weight_unit", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "height_unit", + name: "height_unit", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "length_unit", + name: "length_unit", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "avg_review", + name: "avg_review", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "sale_price", + name: "sale_price", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "shipping_price", + name: "shipping_price", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "regular_price", + name: "regular_price", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "position", + name: "position", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "download_expire_at", + name: "download_expire_at", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "schedule_sale_at", + name: "schedule_sale_at", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "schedule_sale_end", + name: "schedule_sale_end", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "description", + name: "description", + type: "body", + rules: "", + dataType: "String", + value: "", + }, + { + id: "is_virtual", + name: "is_virtual", + type: "body", + rules: "", + dataType: "Boolean", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomProductEditLambda", + name: "Edit Ecom Product Lambda", + method: "PUT", + description: "Edit Product.", + route: "/v2/api/lambda/ecom/product/:id", + inputs: [ + { + id: "id", + name: "id", + type: "path", + rules: "required", + dataType: "Number", + value: "", + }, + { + id: "payload", + name: "payload", + type: "body", + rules: "required", + dataType: "Object", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomProductDeleteLambda", + name: "Delete Ecom Product Lambda", + method: "DELETE", + description: "Delete Product.", + route: "/v2/api/lambda/ecom/product/:id", + inputs: [ + { + id: "id", + name: "id", + type: "path", + rules: "required", + dataType: "Number", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_getCartItems", + name: "Get Cart Items", + method: "GET", + description: "Get cart.", + route: "/v2/api/lambda/ecom/cart", + columns: [], + inputs: [ + { + id: "user_id", + name: "user_id", + type: "query", + rules: "required", + dataType: "Int?", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: [], + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomAddCart", + name: "Ecom Add Cart", + method: "POST", + description: "Add Product to cart.", + route: "/v2/api/lambda/ecom/cart/item", + inputs: [ + { + id: "user_id", + name: "user_id", + type: "body", + rules: "required", + dataType: "Int?", + value: "", + }, + { + id: "productId", + name: "productId", + type: "body", + rules: "required", + dataType: "Int", + value: "", + }, + { + id: "quantity", + name: "quantity", + type: "body", + rules: "required", + dataType: "Int", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomDeleteCartItem", + name: "Ecom delete Cart item", + method: "POST", + description: "Delete Product from cart.", + route: "/v2/api/lambda/ecom/cart/update", + inputs: [ + { + id: "user_id", + name: "user_id", + type: "query", + rules: "required", + dataType: "Int?", + value: "", + }, + { + id: "data", + name: "data", + type: "query", + rules: "required", + dataType: [], + value: "Array", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomGetReviews", + name: "Ecom get product review", + method: "POST", + description: "Get Product Review.", + route: "/v2/api/lambda/ecom/product/review", + inputs: [ + { + id: "productId", + name: "productId", + type: "query", + rules: "required", + dataType: "Int", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: [], + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_ecomAddReviews", + name: "Ecom add product review", + method: "POST", + description: "Add Product Review.", + route: "/v2/api/lambda/ecom/product/review/add", + inputs: [ + { + id: "review", + name: "review", + type: "query", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "productId", + name: "productId", + type: "query", + rules: "required", + dataType: "Int", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "ecom", + }, + { + id: "_forgotPassword", + name: "Forgot Password", + method: "POST", + description: "", + route: "/v2/api/lambda/forgot", + inputs: [ + { + id: "email", + name: "email", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "role", + name: "role", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "forgot", + }, + { + id: "_forgotPasswordMobile", + name: "Forgot Password Mobile", + method: "POSt", + description: "", + route: "/v2/api/lambda/mobile/forgot", + inputs: [ + { + id: "email", + name: "email", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "forgot", + }, + { + id: "_resetPassword", + name: "Reset Password", + method: "POST", + description: "", + route: "/v2/api/lambda/reset", + inputs: [ + { + id: "token", + name: "token", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "code", + name: "code", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "password", + name: "password", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "validation", + key: "validation", + value: "", + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "reset", + }, + { + id: "_resetPasswordMobile", + name: "Reset Password Mobile", + method: "POST", + description: "", + route: "/v2/api/lambda/mobile/reset", + inputs: [ + { + id: "code", + name: "code", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "password", + name: "password", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "validation", + key: "validation", + value: "", + valueType: "Array", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "reset", + }, + { + id: "_getStripeData", + name: "Get Stripe Data", + method: "POST", + description: "Default function for generating stripe data for checkout.", + route: "/v2/api/lambda/stripe/mobile/intent/", + inputs: [ + { + id: "user_id", + name: "user_id", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "amount", + name: "amount", + type: "body", + rules: "required", + dataType: "String", + value: "", + }, + { + id: "currency", + name: "currency", + type: "body", + rules: "optional", + dataType: "String", + value: "", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "false", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "OK", + valueType: "String", + parent: "", + }, + { + id: "paymentIntent", + key: "paymentIntent", + value: "result[0].paymentIntent ?? ''", + valueType: "String", + parent: "", + }, + { + id: "ephemeralKeyRaw", + key: "ephemeralKeyRaw", + value: "result[0].ephemeralKeyRaw ?? ''", + valueType: "String", + parent: "", + }, + { + id: "customer", + key: "customer", + value: "result[0].customer ?? ''", + valueType: "String", + parent: "", + }, + { + id: "publishableKey", + key: "publishableKey", + value: "result[0].publishableKey ?? ''", + valueType: "String", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: false, + authorizedRoles: [], + imports: "", + type: "default", + group: "stripe", + }, + { + id: "_defaultSquareFootCostOneTree", + name: "Get One Default Square Foot Cost", + method: "GET", + description: "", + route: "/v4/api/records/default_square_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingOneTree", + name: "Get One Setting", + method: "GET", + description: "", + route: "/v4/api/records/setting/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costOneTree", + name: "Get One Cost", + method: "GET", + description: "", + route: "/v4/api/records/cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomOneTree", + name: "Get One Room", + method: "GET", + description: "", + route: "/v4/api/records/room/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborOneTree", + name: "Get One Labor", + method: "GET", + description: "", + route: "/v4/api/records/labor/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryOneTree", + name: "Get One Line Item Entry", + method: "GET", + description: "", + route: "/v4/api/records/line_item_entry/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsOneTree", + name: "Get One Company Settings", + method: "GET", + description: "", + route: "/v4/api/records/company_settings/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsOneTree", + name: "Get One Cms", + method: "GET", + description: "", + route: "/v4/api/records/cms/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberOneTree", + name: "Get One Team Member", + method: "GET", + description: "", + route: "/v4/api/records/team_member/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialOneTree", + name: "Get One Default Material", + method: "GET", + description: "", + route: "/v4/api/records/default_material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectOneTree", + name: "Get One Project", + method: "GET", + description: "", + route: "/v4/api/records/project/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userOneTree", + name: "Get One User", + method: "GET", + description: "", + route: "/v4/api/records/user/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profileOneTree", + name: "Get One Profile", + method: "GET", + description: "", + route: "/v4/api/records/profile/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostOneTree", + name: "Get One Lineal Foot Cost", + method: "GET", + description: "", + route: "/v4/api/records/lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerOneTree", + name: "Get One Customer", + method: "GET", + description: "", + route: "/v4/api/records/customer/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionOneTree", + name: "Get One Permission", + method: "GET", + description: "", + route: "/v4/api/records/permission/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenOneTree", + name: "Get One Token", + method: "GET", + description: "", + route: "/v4/api/records/token/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsOneTree", + name: "Get One Sqft Costs", + method: "GET", + description: "", + route: "/v4/api/records/sqft_costs/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailOneTree", + name: "Get One Email", + method: "GET", + description: "", + route: "/v4/api/records/email/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsOneTree", + name: "Get One Alerts", + method: "GET", + description: "", + route: "/v4/api/records/alerts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsOneTree", + name: "Get One Draws", + method: "GET", + description: "", + route: "/v4/api/records/draws/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatOneTree", + name: "Get One Chat", + method: "GET", + description: "", + route: "/v4/api/records/chat/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialOneTree", + name: "Get One Material", + method: "GET", + description: "", + route: "/v4/api/records/material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoiceOneTree", + name: "Get One Invoice", + method: "GET", + description: "", + route: "/v4/api/records/invoice/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostOneTree", + name: "Get One Default Lineal Foot Cost", + method: "GET", + description: "", + route: "/v4/api/records/default_lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypeOneTree", + name: "Get One Trigger Type", + method: "GET", + description: "", + route: "/v4/api/records/trigger_type/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobOneTree", + name: "Get One Job", + method: "GET", + description: "", + route: "/v4/api/records/job/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsOneTree", + name: "Get One Line Items", + method: "GET", + description: "", + route: "/v4/api/records/line_items/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoOneTree", + name: "Get One Photo", + method: "GET", + description: "", + route: "/v4/api/records/photo/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysOneTree", + name: "Get One Api Keys", + method: "GET", + description: "", + route: "/v4/api/records/api_keys/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionOneTree", + name: "Get One Change Order Description", + method: "GET", + description: "", + route: "/v4/api/records/change_order_description/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogOneTree", + name: "Get One Analytic Log", + method: "GET", + description: "", + route: "/v4/api/records/analytic_log/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsOneTree", + name: "Get One Posts", + method: "GET", + description: "", + route: "/v4/api/records/posts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeeOneTree", + name: "Get One Employee", + method: "GET", + description: "", + route: "/v4/api/records/employee/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "model", + key: "model", + value: "", + valueType: "Object", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultSquareFootCostListTree", + name: "Get Default Square Foot Cost List", + method: "GET", + description: "", + route: "/v4/api/records/default_square_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingListTree", + name: "Get Setting List", + method: "GET", + description: "", + route: "/v4/api/records/setting", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costListTree", + name: "Get Cost List", + method: "GET", + description: "", + route: "/v4/api/records/cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomListTree", + name: "Get Room List", + method: "GET", + description: "", + route: "/v4/api/records/room", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborListTree", + name: "Get Labor List", + method: "GET", + description: "", + route: "/v4/api/records/labor", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryListTree", + name: "Get Line Item Entry List", + method: "GET", + description: "", + route: "/v4/api/records/line_item_entry", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsListTree", + name: "Get Company Settings List", + method: "GET", + description: "", + route: "/v4/api/records/company_settings", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsListTree", + name: "Get Cms List", + method: "GET", + description: "", + route: "/v4/api/records/cms", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberListTree", + name: "Get Team Member List", + method: "GET", + description: "", + route: "/v4/api/records/team_member", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialListTree", + name: "Get Default Material List", + method: "GET", + description: "", + route: "/v4/api/records/default_material", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectListTree", + name: "Get Project List", + method: "GET", + description: "", + route: "/v4/api/records/project", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userListTree", + name: "Get User List", + method: "GET", + description: "", + route: "/v4/api/records/user", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profileListTree", + name: "Get Profile List", + method: "GET", + description: "", + route: "/v4/api/records/profile", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostListTree", + name: "Get Lineal Foot Cost List", + method: "GET", + description: "", + route: "/v4/api/records/lineal_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerListTree", + name: "Get Customer List", + method: "GET", + description: "", + route: "/v4/api/records/customer", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionListTree", + name: "Get Permission List", + method: "GET", + description: "", + route: "/v4/api/records/permission", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenListTree", + name: "Get Token List", + method: "GET", + description: "", + route: "/v4/api/records/token", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsListTree", + name: "Get Sqft Costs List", + method: "GET", + description: "", + route: "/v4/api/records/sqft_costs", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailListTree", + name: "Get Email List", + method: "GET", + description: "", + route: "/v4/api/records/email", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsListTree", + name: "Get Alerts List", + method: "GET", + description: "", + route: "/v4/api/records/alerts", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsListTree", + name: "Get Draws List", + method: "GET", + description: "", + route: "/v4/api/records/draws", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatListTree", + name: "Get Chat List", + method: "GET", + description: "", + route: "/v4/api/records/chat", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialListTree", + name: "Get Material List", + method: "GET", + description: "", + route: "/v4/api/records/material", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoiceListTree", + name: "Get Invoice List", + method: "GET", + description: "", + route: "/v4/api/records/invoice", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostListTree", + name: "Get Default Lineal Foot Cost List", + method: "GET", + description: "", + route: "/v4/api/records/default_lineal_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypeListTree", + name: "Get Trigger Type List", + method: "GET", + description: "", + route: "/v4/api/records/trigger_type", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobListTree", + name: "Get Job List", + method: "GET", + description: "", + route: "/v4/api/records/job", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsListTree", + name: "Get Line Items List", + method: "GET", + description: "", + route: "/v4/api/records/line_items", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoListTree", + name: "Get Photo List", + method: "GET", + description: "", + route: "/v4/api/records/photo", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysListTree", + name: "Get Api Keys List", + method: "GET", + description: "", + route: "/v4/api/records/api_keys", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionListTree", + name: "Get Change Order Description List", + method: "GET", + description: "", + route: "/v4/api/records/change_order_description", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogListTree", + name: "Get Analytic Log List", + method: "GET", + description: "", + route: "/v4/api/records/analytic_log", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsListTree", + name: "Get Posts List", + method: "GET", + description: "", + route: "/v4/api/records/posts", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeeListTree", + name: "Get Employee List", + method: "GET", + description: "", + route: "/v4/api/records/employee", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "size", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultSquareFootCostPaginatedTree", + name: "Get Default Square Foot Cost Paginated", + method: "GET", + description: "", + route: "/v4/api/records/default_square_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingPaginatedTree", + name: "Get Setting Paginated", + method: "GET", + description: "", + route: "/v4/api/records/setting", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costPaginatedTree", + name: "Get Cost Paginated", + method: "GET", + description: "", + route: "/v4/api/records/cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomPaginatedTree", + name: "Get Room Paginated", + method: "GET", + description: "", + route: "/v4/api/records/room", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborPaginatedTree", + name: "Get Labor Paginated", + method: "GET", + description: "", + route: "/v4/api/records/labor", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryPaginatedTree", + name: "Get Line Item Entry Paginated", + method: "GET", + description: "", + route: "/v4/api/records/line_item_entry", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsPaginatedTree", + name: "Get Company Settings Paginated", + method: "GET", + description: "", + route: "/v4/api/records/company_settings", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsPaginatedTree", + name: "Get Cms Paginated", + method: "GET", + description: "", + route: "/v4/api/records/cms", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberPaginatedTree", + name: "Get Team Member Paginated", + method: "GET", + description: "", + route: "/v4/api/records/team_member", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialPaginatedTree", + name: "Get Default Material Paginated", + method: "GET", + description: "", + route: "/v4/api/records/default_material", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectPaginatedTree", + name: "Get Project Paginated", + method: "GET", + description: "", + route: "/v4/api/records/project", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userPaginatedTree", + name: "Get User Paginated", + method: "GET", + description: "", + route: "/v4/api/records/user", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profilePaginatedTree", + name: "Get Profile Paginated", + method: "GET", + description: "", + route: "/v4/api/records/profile", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostPaginatedTree", + name: "Get Lineal Foot Cost Paginated", + method: "GET", + description: "", + route: "/v4/api/records/lineal_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerPaginatedTree", + name: "Get Customer Paginated", + method: "GET", + description: "", + route: "/v4/api/records/customer", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionPaginatedTree", + name: "Get Permission Paginated", + method: "GET", + description: "", + route: "/v4/api/records/permission", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenPaginatedTree", + name: "Get Token Paginated", + method: "GET", + description: "", + route: "/v4/api/records/token", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsPaginatedTree", + name: "Get Sqft Costs Paginated", + method: "GET", + description: "", + route: "/v4/api/records/sqft_costs", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailPaginatedTree", + name: "Get Email Paginated", + method: "GET", + description: "", + route: "/v4/api/records/email", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsPaginatedTree", + name: "Get Alerts Paginated", + method: "GET", + description: "", + route: "/v4/api/records/alerts", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsPaginatedTree", + name: "Get Draws Paginated", + method: "GET", + description: "", + route: "/v4/api/records/draws", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatPaginatedTree", + name: "Get Chat Paginated", + method: "GET", + description: "", + route: "/v4/api/records/chat", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialPaginatedTree", + name: "Get Material Paginated", + method: "GET", + description: "", + route: "/v4/api/records/material", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoicePaginatedTree", + name: "Get Invoice Paginated", + method: "GET", + description: "", + route: "/v4/api/records/invoice", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostPaginatedTree", + name: "Get Default Lineal Foot Cost Paginated", + method: "GET", + description: "", + route: "/v4/api/records/default_lineal_foot_cost", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypePaginatedTree", + name: "Get Trigger Type Paginated", + method: "GET", + description: "", + route: "/v4/api/records/trigger_type", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobPaginatedTree", + name: "Get Job Paginated", + method: "GET", + description: "", + route: "/v4/api/records/job", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsPaginatedTree", + name: "Get Line Items Paginated", + method: "GET", + description: "", + route: "/v4/api/records/line_items", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoPaginatedTree", + name: "Get Photo Paginated", + method: "GET", + description: "", + route: "/v4/api/records/photo", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysPaginatedTree", + name: "Get Api Keys Paginated", + method: "GET", + description: "", + route: "/v4/api/records/api_keys", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionPaginatedTree", + name: "Get Change Order Description Paginated", + method: "GET", + description: "", + route: "/v4/api/records/change_order_description", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogPaginatedTree", + name: "Get Analytic Log Paginated", + method: "GET", + description: "", + route: "/v4/api/records/analytic_log", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsPaginatedTree", + name: "Get Posts Paginated", + method: "GET", + description: "", + route: "/v4/api/records/posts", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeePaginatedTree", + name: "Get Employee Paginated", + method: "GET", + description: "", + route: "/v4/api/records/employee", + inputs: [ + { + name: "order", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "page", + type: "query", + rules: "required", + dataType: "String?", + }, + { + name: "filter", + type: "query", + rules: "", + dataType: "String?", + }, + { + name: "join", + type: "query", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "list", + key: "list", + value: "", + valueType: "Array", + parent: "", + }, + { + id: "page", + key: "page", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "limit", + key: "limit", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "total", + key: "total", + value: "", + valueType: "Number", + parent: "", + }, + { + id: "mapping", + key: "mapping", + value: "", + valueType: "Object", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultSquareFootCostCreateTree", + name: "Create Default Square Foot Cost", + method: "POST", + description: "", + route: "/v4/api/records/default_square_foot_cost", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingCreateTree", + name: "Create Setting", + method: "POST", + description: "", + route: "/v4/api/records/setting", + inputs: [ + { + name: "setting_key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "setting_value", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costCreateTree", + name: "Create Cost", + method: "POST", + description: "", + route: "/v4/api/records/cost", + inputs: [ + { + name: "cost_type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "unit_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomCreateTree", + name: "Create Room", + method: "POST", + description: "", + route: "/v4/api/records/room", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "other_user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "chat_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "unread", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "user_update_at", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "other_user_update_at", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborCreateTree", + name: "Create Labor", + method: "POST", + description: "", + route: "/v4/api/records/labor", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hours", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "amount", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "per_hour", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryCreateTree", + name: "Create Line Item Entry", + method: "POST", + description: "", + route: "/v4/api/records/line_item_entry", + inputs: [ + { + name: "parent_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "line_item_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "quantity", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsCreateTree", + name: "Create Company Settings", + method: "POST", + description: "", + route: "/v4/api/records/company_settings", + inputs: [ + { + name: "default_hourly_rate", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "default_profit_overhead", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsCreateTree", + name: "Create Cms", + method: "POST", + description: "", + route: "/v4/api/records/cms", + inputs: [ + { + name: "page", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_value", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberCreateTree", + name: "Create Team Member", + method: "POST", + description: "", + route: "/v4/api/records/team_member", + inputs: [ + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hourly_rate", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "is_default", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialCreateTree", + name: "Create Default Material", + method: "POST", + description: "", + route: "/v4/api/records/default_material", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectCreateTree", + name: "Create Project", + method: "POST", + description: "", + route: "/v4/api/records/project", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "change_count", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "customer_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "hourly_rate", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userCreateTree", + name: "Create User", + method: "POST", + description: "", + route: "/v4/api/records/user", + inputs: [ + { + name: "oauth", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "first_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "last_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "password", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "verify", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "company_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "photo", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "refer", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "stripe_uid", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "paypal_uid", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "two_factor_authentication", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profileCreateTree", + name: "Create Profile", + method: "POST", + description: "", + route: "/v4/api/records/profile", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "fcm_token", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "device_id", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "device_type", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostCreateTree", + name: "Create Lineal Foot Cost", + method: "POST", + description: "", + route: "/v4/api/records/lineal_foot_cost", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerCreateTree", + name: "Create Customer", + method: "POST", + description: "", + route: "/v4/api/records/customer", + inputs: [ + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "address", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionCreateTree", + name: "Create Permission", + method: "POST", + description: "", + route: "/v4/api/records/permission", + inputs: [ + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "permission", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenCreateTree", + name: "Create Token", + method: "POST", + description: "", + route: "/v4/api/records/token", + inputs: [ + { + name: "token", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "expire_at", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsCreateTree", + name: "Create Sqft Costs", + method: "POST", + description: "", + route: "/v4/api/records/sqft_costs", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailCreateTree", + name: "Create Email", + method: "POST", + description: "", + route: "/v4/api/records/email", + inputs: [ + { + name: "slug", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "subject", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "tag", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "html", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsCreateTree", + name: "Create Alerts", + method: "POST", + description: "", + route: "/v4/api/records/alerts", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "message", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "image", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "is_read", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsCreateTree", + name: "Create Draws", + method: "POST", + description: "", + route: "/v4/api/records/draws", + inputs: [ + { + name: "amount_paid", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "check_no", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "amount", + type: "body", + rules: "", + dataType: "decimal?", + }, + { + name: "percentage", + type: "body", + rules: "", + dataType: "decimal?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "payment_type", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatCreateTree", + name: "Create Chat", + method: "POST", + description: "", + route: "/v4/api/records/chat", + inputs: [ + { + name: "room_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "unread", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "chat", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialCreateTree", + name: "Create Material", + method: "POST", + description: "", + route: "/v4/api/records/material", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "unit_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoiceCreateTree", + name: "Create Invoice", + method: "POST", + description: "", + route: "/v4/api/records/invoice", + inputs: [ + { + name: "company_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "address", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "milestone_description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "total_amount_due", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostCreateTree", + name: "Create Default Lineal Foot Cost", + method: "POST", + description: "", + route: "/v4/api/records/default_lineal_foot_cost", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypeCreateTree", + name: "Create Trigger Type", + method: "POST", + description: "", + route: "/v4/api/records/trigger_type", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobCreateTree", + name: "Create Job", + method: "POST", + description: "", + route: "/v4/api/records/job", + inputs: [ + { + name: "task", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "arguments", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "error_log", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "identifier", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "retries", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "retry_count", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "time_interval", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "last_run", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsCreateTree", + name: "Create Line Items", + method: "POST", + description: "", + route: "/v4/api/records/line_items", + inputs: [ + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "estimated_by", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "labor_hours", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoCreateTree", + name: "Create Photo", + method: "POST", + description: "", + route: "/v4/api/records/photo", + inputs: [ + { + name: "url", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "caption", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "width", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "height", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysCreateTree", + name: "Create Api Keys", + method: "POST", + description: "", + route: "/v4/api/records/api_keys", + inputs: [ + { + name: "key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "value", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionCreateTree", + name: "Create Change Order Description", + method: "POST", + description: "", + route: "/v4/api/records/change_order_description", + inputs: [ + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "line_item_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogCreateTree", + name: "Create Analytic Log", + method: "POST", + description: "", + route: "/v4/api/records/analytic_log", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "url", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "path", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hostname", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "ip", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "browser", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "country", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsCreateTree", + name: "Create Posts", + method: "POST", + description: "", + route: "/v4/api/records/posts", + inputs: [ + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "links", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeeCreateTree", + name: "Create Employee", + method: "POST", + description: "", + route: "/v4/api/records/employee", + inputs: [ + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "default_hourly_rate", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "default_profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultSquareFootCostUpdateTree", + name: "Update Default Square Foot Cost", + method: "PUT", + description: "", + route: "/v4/api/records/default_square_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingUpdateTree", + name: "Update Setting", + method: "PUT", + description: "", + route: "/v4/api/records/setting/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "setting_key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "setting_value", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costUpdateTree", + name: "Update Cost", + method: "PUT", + description: "", + route: "/v4/api/records/cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "cost_type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "unit_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomUpdateTree", + name: "Update Room", + method: "PUT", + description: "", + route: "/v4/api/records/room/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "other_user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "chat_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "unread", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "user_update_at", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "other_user_update_at", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborUpdateTree", + name: "Update Labor", + method: "PUT", + description: "", + route: "/v4/api/records/labor/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hours", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "amount", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "per_hour", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryUpdateTree", + name: "Update Line Item Entry", + method: "PUT", + description: "", + route: "/v4/api/records/line_item_entry/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "parent_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "line_item_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "quantity", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsUpdateTree", + name: "Update Company Settings", + method: "PUT", + description: "", + route: "/v4/api/records/company_settings/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "default_hourly_rate", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "default_profit_overhead", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsUpdateTree", + name: "Update Cms", + method: "PUT", + description: "", + route: "/v4/api/records/cms/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "page", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "content_value", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberUpdateTree", + name: "Update Team Member", + method: "PUT", + description: "", + route: "/v4/api/records/team_member/:id", + inputs: [ + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hourly_rate", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "is_default", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialUpdateTree", + name: "Update Default Material", + method: "PUT", + description: "", + route: "/v4/api/records/default_material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectUpdateTree", + name: "Update Project", + method: "PUT", + description: "", + route: "/v4/api/records/project/:id", + inputs: [ + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "change_count", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "customer_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "hourly_rate", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userUpdateTree", + name: "Update User", + method: "PUT", + description: "", + route: "/v4/api/records/user/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "oauth", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "first_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "last_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "password", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "verify", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "company_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "photo", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "refer", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "stripe_uid", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "paypal_uid", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "two_factor_authentication", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profileUpdateTree", + name: "Update Profile", + method: "PUT", + description: "", + route: "/v4/api/records/profile/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "fcm_token", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "device_id", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "device_type", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostUpdateTree", + name: "Update Lineal Foot Cost", + method: "PUT", + description: "", + route: "/v4/api/records/lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerUpdateTree", + name: "Update Customer", + method: "PUT", + description: "", + route: "/v4/api/records/customer/:id", + inputs: [ + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "phone", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "address", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionUpdateTree", + name: "Update Permission", + method: "PUT", + description: "", + route: "/v4/api/records/permission/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "permission", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenUpdateTree", + name: "Update Token", + method: "PUT", + description: "", + route: "/v4/api/records/token/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "token", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "expire_at", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsUpdateTree", + name: "Update Sqft Costs", + method: "PUT", + description: "", + route: "/v4/api/records/sqft_costs/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "lineal_foot_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "material_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailUpdateTree", + name: "Update Email", + method: "PUT", + description: "", + route: "/v4/api/records/email/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "slug", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "subject", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "tag", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "html", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsUpdateTree", + name: "Update Alerts", + method: "PUT", + description: "", + route: "/v4/api/records/alerts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "message", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "image", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "is_read", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsUpdateTree", + name: "Update Draws", + method: "PUT", + description: "", + route: "/v4/api/records/draws/:id", + inputs: [ + { + name: "amount_paid", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "check_no", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "amount", + type: "body", + rules: "", + dataType: "decimal?", + }, + { + name: "percentage", + type: "body", + rules: "", + dataType: "decimal?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "payment_type", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatUpdateTree", + name: "Update Chat", + method: "PUT", + description: "", + route: "/v4/api/records/chat/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "room_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "unread", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "chat", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialUpdateTree", + name: "Update Material", + method: "PUT", + description: "", + route: "/v4/api/records/material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "unit_cost", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoiceUpdateTree", + name: "Update Invoice", + method: "PUT", + description: "", + route: "/v4/api/records/invoice/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "company_name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "email", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "address", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "milestone_description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "total_amount_due", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostUpdateTree", + name: "Update Default Lineal Foot Cost", + method: "PUT", + description: "", + route: "/v4/api/records/default_lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "labor_cost", + type: "body", + rules: "", + dataType: "Number?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypeUpdateTree", + name: "Update Trigger Type", + method: "PUT", + description: "", + route: "/v4/api/records/trigger_type/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "name", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobUpdateTree", + name: "Update Job", + method: "PUT", + description: "", + route: "/v4/api/records/job/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "task", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "arguments", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "error_log", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "identifier", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "retries", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "retry_count", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "time_interval", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "last_run", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsUpdateTree", + name: "Update Line Items", + method: "PUT", + description: "", + route: "/v4/api/records/line_items/:id", + inputs: [ + { + name: "hidden", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "project_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "estimated_by", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "labor_hours", + type: "body", + rules: "", + dataType: "Number?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoUpdateTree", + name: "Update Photo", + method: "PUT", + description: "", + route: "/v4/api/records/photo/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "url", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "caption", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "width", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "height", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysUpdateTree", + name: "Update Api Keys", + method: "PUT", + description: "", + route: "/v4/api/records/api_keys/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "key", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "value", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionUpdateTree", + name: "Update Change Order Description", + method: "PUT", + description: "", + route: "/v4/api/records/change_order_description/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "description", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "line_item_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogUpdateTree", + name: "Update Analytic Log", + method: "PUT", + description: "", + route: "/v4/api/records/analytic_log/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "url", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "path", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "hostname", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "ip", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "role", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "browser", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "country", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsUpdateTree", + name: "Update Posts", + method: "PUT", + description: "", + route: "/v4/api/records/posts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "status", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "type", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "data", + type: "body", + rules: "", + dataType: "String?", + }, + { + name: "links", + type: "body", + rules: "", + dataType: "String?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeeUpdateTree", + name: "Update Employee", + method: "PUT", + description: "", + route: "/v4/api/records/employee/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + { + name: "user_id", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "default_hourly_rate", + type: "body", + rules: "", + dataType: "Integer?", + }, + { + name: "default_profit_overhead", + type: "body", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultSquareFootCostDeleteTree", + name: "Delete Default Square Foot Cost", + method: "DELETE", + description: "", + route: "/v4/api/records/default_square_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_settingDeleteTree", + name: "Delete Setting", + method: "DELETE", + description: "", + route: "/v4/api/records/setting/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + setting_key: "varchar", + setting_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_costDeleteTree", + name: "Delete Cost", + method: "DELETE", + description: "", + route: "/v4/api/records/cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + cost_type: "varchar", + name: "varchar", + unit_cost: "int", + lineal_foot_cost: "int", + labor_cost: "int", + material_cost: "int", + profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_roomDeleteTree", + name: "Delete Room", + method: "DELETE", + description: "", + route: "/v4/api/records/room/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + other_user_id: "int", + chat_id: "int", + unread: "int", + create_at: "date", + update_at: "datetime", + user_update_at: "datetime", + other_user_update_at: "datetime", + }, + }, + { + id: "_laborDeleteTree", + name: "Delete Labor", + method: "DELETE", + description: "", + route: "/v4/api/records/labor/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + hours: "varchar", + amount: "int", + per_hour: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemEntryDeleteTree", + name: "Delete Line Item Entry", + method: "DELETE", + description: "", + route: "/v4/api/records/line_item_entry/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + parent_id: "int", + name: "varchar", + cost: "double", + labor_cost: "double", + line_item_id: "int", + quantity: "double", + }, + }, + { + id: "_companySettingsDeleteTree", + name: "Delete Company Settings", + method: "DELETE", + description: "", + route: "/v4/api/records/company_settings/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + default_hourly_rate: "double", + default_profit_overhead: "double", + user_id: "int", + }, + }, + { + id: "_cmsDeleteTree", + name: "Delete Cms", + method: "DELETE", + description: "", + route: "/v4/api/records/cms/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + page: "varchar", + content_key: "varchar", + content_type: "varchar", + content_value: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_teamMemberDeleteTree", + name: "Delete Team Member", + method: "DELETE", + description: "", + route: "/v4/api/records/team_member/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + project_id: "int", + id: "int", + user_id: "int", + name: "varchar", + hourly_rate: "int", + is_default: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultMaterialDeleteTree", + name: "Delete Default Material", + method: "DELETE", + description: "", + route: "/v4/api/records/default_material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + user_id: "varchar", + cost: "varchar", + name: "varchar", + hidden: "int", + }, + }, + { + id: "_projectDeleteTree", + name: "Delete Project", + method: "DELETE", + description: "", + route: "/v4/api/records/project/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + name: "text", + change_count: "int", + id: "int", + customer_id: "int", + user_id: "int", + status: "int", + profit_overhead: "double", + hourly_rate: "double", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_userDeleteTree", + name: "Delete User", + method: "DELETE", + description: "", + route: "/v4/api/records/user/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + oauth: "varchar", + role: "varchar", + first_name: "varchar", + last_name: "varchar", + email: "varchar", + password: "varchar", + type: "int", + verify: "int", + phone: "varchar", + company_name: "varchar", + photo: "text", + refer: "varchar", + stripe_uid: "varchar", + paypal_uid: "varchar", + two_factor_authentication: "int", + status: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_profileDeleteTree", + name: "Delete Profile", + method: "DELETE", + description: "", + route: "/v4/api/records/profile/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + create_at: "date", + fcm_token: "text", + device_id: "text", + device_type: "text", + update_at: "datetime", + }, + }, + { + id: "_linealFootCostDeleteTree", + name: "Delete Lineal Foot Cost", + method: "DELETE", + description: "", + route: "/v4/api/records/lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_customerDeleteTree", + name: "Delete Customer", + method: "DELETE", + description: "", + route: "/v4/api/records/customer/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + status: "int", + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + email: "varchar", + phone: "varchar", + address: "varchar", + user_id: "varchar", + }, + }, + { + id: "_permissionDeleteTree", + name: "Delete Permission", + method: "DELETE", + description: "", + route: "/v4/api/records/permission/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + role: "varchar", + permission: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_tokenDeleteTree", + name: "Delete Token", + method: "DELETE", + description: "", + route: "/v4/api/records/token/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + token: "text", + type: "int", + data: "text", + user_id: "int", + status: "int", + create_at: "date", + update_at: "datetime", + expire_at: "datetime", + }, + }, + { + id: "_sqftCostsDeleteTree", + name: "Delete Sqft Costs", + method: "DELETE", + description: "", + route: "/v4/api/records/sqft_costs/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + lineal_foot_cost: "int", + profit_overhead: "int", + labor_cost: "int", + material_cost: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_emailDeleteTree", + name: "Delete Email", + method: "DELETE", + description: "", + route: "/v4/api/records/email/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + slug: "varchar", + subject: "text", + tag: "text", + html: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_alertsDeleteTree", + name: "Delete Alerts", + method: "DELETE", + description: "", + route: "/v4/api/records/alerts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + message: "text", + image: "text", + is_read: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_drawsDeleteTree", + name: "Delete Draws", + method: "DELETE", + description: "", + route: "/v4/api/records/draws/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + amount_paid: "int", + id: "int", + check_no: "varchar", + amount: "decimal", + percentage: "decimal", + description: "text", + create_at: "date", + update_at: "datetime", + status: "int", + project_id: "int", + payment_type: "varchar", + }, + }, + { + id: "_chatDeleteTree", + name: "Delete Chat", + method: "DELETE", + description: "", + route: "/v4/api/records/chat/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + room_id: "int", + unread: "int", + chat: "longtext", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_materialDeleteTree", + name: "Delete Material", + method: "DELETE", + description: "", + route: "/v4/api/records/material/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "varchar", + unit_cost: "int", + create_at: "date", + update_at: "datetime", + project_id: "varchar", + }, + }, + { + id: "_invoiceDeleteTree", + name: "Delete Invoice", + method: "DELETE", + description: "", + route: "/v4/api/records/invoice/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + company_name: "varchar", + name: "varchar", + email: "varchar", + address: "varchar", + milestone_description: "varchar", + total_amount_due: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_defaultLinealFootCostDeleteTree", + name: "Delete Default Lineal Foot Cost", + method: "DELETE", + description: "", + route: "/v4/api/records/default_lineal_foot_cost/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + create_at: "date", + update_at: "datetime", + name: "varchar", + cost: "double", + labor_cost: "double", + user_id: "int", + hidden: "int", + }, + }, + { + id: "_triggerTypeDeleteTree", + name: "Delete Trigger Type", + method: "DELETE", + description: "", + route: "/v4/api/records/trigger_type/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + name: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_jobDeleteTree", + name: "Delete Job", + method: "DELETE", + description: "", + route: "/v4/api/records/job/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + task: "text", + arguments: "text", + error_log: "text", + identifier: "varchar", + retries: "int", + retry_count: "int", + time_interval: "varchar", + last_run: "datetime", + status: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_lineItemsDeleteTree", + name: "Delete Line Items", + method: "DELETE", + description: "", + route: "/v4/api/records/line_items/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + hidden: "int", + id: "int", + project_id: "int", + description: "varchar", + estimated_by: "varchar", + create_at: "date", + update_at: "datetime", + labor_hours: "double", + }, + }, + { + id: "_photoDeleteTree", + name: "Delete Photo", + method: "DELETE", + description: "", + route: "/v4/api/records/photo/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + url: "text", + caption: "text", + user_id: "int", + width: "int", + height: "int", + type: "int", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_apiKeysDeleteTree", + name: "Delete Api Keys", + method: "DELETE", + description: "", + route: "/v4/api/records/api_keys/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + key: "varchar", + value: "text", + description: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_changeOrderDescriptionDeleteTree", + name: "Delete Change Order Description", + method: "DELETE", + description: "", + route: "/v4/api/records/change_order_description/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + update_at: "datetime", + create_at: "date", + id: "int", + description: "text", + line_item_id: "int", + }, + }, + { + id: "_analyticLogDeleteTree", + name: "Delete Analytic Log", + method: "DELETE", + description: "", + route: "/v4/api/records/analytic_log/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "bigint", + user_id: "int", + url: "text", + path: "text", + hostname: "text", + ip: "varchar", + role: "varchar", + browser: "varchar", + country: "varchar", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_postsDeleteTree", + name: "Delete Posts", + method: "DELETE", + description: "", + route: "/v4/api/records/posts/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + status: "tinyint", + type: "text", + data: "text", + links: "text", + create_at: "date", + update_at: "datetime", + }, + }, + { + id: "_employeeDeleteTree", + name: "Delete Employee", + method: "DELETE", + description: "", + route: "/v4/api/records/employee/:id", + inputs: [ + { + name: "id", + type: "path", + rules: "", + dataType: "Integer?", + }, + ], + response: [ + { + id: "error", + key: "error", + value: "", + valueType: "Boolean", + parent: "", + }, + { + id: "message", + key: "message", + value: "", + valueType: "String", + parent: "", + }, + { + id: "data", + key: "data", + value: "", + valueType: "Integer", + parent: "", + }, + ], + code: "", + doc: "", + unit: "", + protected: true, + authorizedRoles: [], + imports: "", + type: "default", + group: "treeql", + columns: { + id: "int", + user_id: "int", + default_hourly_rate: "int", + default_profit_overhead: "int", + create_at: "date", + update_at: "datetime", + }, + }, + ], + ui: [ + { + id: "cedf5140-1c20-660c-774d-a6d36bfb223b", + name: "Accountview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 1, + components: [], + id: "e40754ef-7303-e432-4049-dd621424dc48", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cedf5140-1c20-660c-774d-a6d36bfb223b", + children: [], + }, + ], + }, + { + id: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + name: "Addmaterial", + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: 16, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + pageId: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + id: "993807ed-1158-2d72-23f3-2281e5855e75", + children: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "i0glnmyu8ekz-xn95dj-j9ao2y-8rmcz2-mzjszfbrwvqtiuyjy5", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Unit Cost", + }, + propTypes: { + text: "text", + }, + id: "tt5o08am1y2a-2xqfu6-d6uihy-ifafi6-6pkk450e90vpyzhs1p", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "true", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Cancel", + onclick: "submit", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ldlk8cm79j48-x1lipf-zu7n13-9y2m5r-56qwl7hezv22qmtx0u", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Submit", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "rhygz41im004-vtsqb1-kbbhpd-6sjd53-sjm3cvaqofck1r1ok0", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + ], + }, + { + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + name: "Companysetup", + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "5cedc397-73ca-0247-05e7-f5c32deee49d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "f13a11ee-c0f8-d9e4-f435-eeade06546dc", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Profit Overhead", + }, + propTypes: { + text: "text", + }, + id: "464ba6e4-7c4e-db6f-7af8-b2a742769221", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "2f313e36-566f-e504-34d5-8356db95861d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Workers", + }, + propTypes: { + text: "text", + }, + id: "27ff1748-a96a-9384-c3e0-d4d92fb3c018", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "0bc73012-cb2a-1781-7569-841891167249", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "771db74e-37c6-c6cd-c62d-b1197ead23b1", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "+ Add", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "de33bc49-74a1-735c-bc26-4f2dbde093ff", + parentId: "2f313e36-566f-e504-34d5-8356db95861d", + parentName: "RelativeLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 14, + components: [], + id: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "b5480a18-8c78-996e-9717-3174639c8229", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save & Continue", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "945e2d15-15fd-f4d2-a353-4b1157348d5d", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + id: "5d406458-0ce8-beab-c688-eb363661dad1", + name: "Costview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 3, + components: [], + id: "c0d0f5da-9028-41d6-cb9f-bef20f99a288", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "5d406458-0ce8-beab-c688-eb363661dad1", + children: [], + }, + ], + }, + { + id: "21324f55-dbc1-a71e-c420-7aed7669de2f", + name: "Dashboardview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 4, + components: [], + id: "77f1c763-cf22-e4c0-ab68-bb6edc2475dd", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "21324f55-dbc1-a71e-c420-7aed7669de2f", + children: [], + }, + ], + }, + { + id: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + name: "Home", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 5, + components: [], + id: "7a5b7443-6f9d-68c0-c878-86af04ce6636", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + children: [], + }, + ], + }, + { + id: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + name: "LabortrackingView", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 6, + components: [], + id: "8e83f3a7-4bd2-3e3c-f458-00a4c7ead46c", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + children: [], + }, + ], + }, + { + id: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + name: "Linealfootsetup", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "99e555d4-d5bd-d22c-d852-bc5ced874f63", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add New Lineal foot cost", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ce83daf4-1e5d-6e1f-2f8e-1ef9ed13ac5b", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "0e6bb1f7-63e2-b483-1e16-91236a95bde7", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + id: "57629038-3779-61e4-9222-413fba948f6d", + name: "Materiallist", + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "930da8c7-1e04-545d-49c1-93338ae5a03c", + pageId: "57629038-3779-61e4-9222-413fba948f6d", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "", + toLeftOf: "", + toRightOf: "parent", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "true", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "3df228c4-b4e6-812a-6851-d7dae0756c38", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + }, + { + type: "layout", + name: "RecyclerView", + component: "DATA_COMPONENT", + icon: "https://cdn-icons-png.flaticon.com/512/4997/4997760.png", + order: -1, + components: [], + props: { + name: "Data", + fields: "id, name, unit_cost", + pass_data: true, + layout_manager: "linear", + columns: "2", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + name: "text", + fields: "text", + pass_data: "boolean", + layout_manager: "options_linear:grid", + columns: "options_1:2:3:4:5:6:7:8", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "084bf25e-2763-3548-dcbf-42f337390e95", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + dataSource: "_materialListTree", + dataSourceName: "Get Material List", + }, + ], + }, + ], + }, + { + id: "a763bdbe-c58c-0ed1-110d-00711065d256", + name: "Materialsetup", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "402b8e07-3b82-9324-8133-36f1783d0243", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "a763bdbe-c58c-0ed1-110d-00711065d256", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "32747828-0ee7-b69d-b9c1-585f02ba0eab", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "62cf8ff1-37d9-1ebf-479f-99c29d0d7700", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + id: "63924326-339a-399f-41cf-092404a69bca", + name: "Projectview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 7, + components: [], + id: "95f48c05-63a7-07e9-820e-2924141a7c0b", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "63924326-339a-399f-41cf-092404a69bca", + children: [], + }, + ], + }, + { + id: "e4621fcf-2b34-dfd9-bd36-556d21401819", + name: "Subcriptionfragment", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 10, + components: [], + id: "951d1db9-3a90-03f5-9fec-40be63508d25", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Subscription", + }, + propTypes: { + text: "text", + }, + id: "03bafcc0-eff8-418a-de97-55614e63912d", + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "29e2d580-570d-0f0d-8689-f2e0a051d392", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "$45 / Month", + }, + propTypes: { + text: "text", + }, + id: "4999v4boh74v-g7rs3p-910lm0-089xyz-zsrux5qqk05i06j5qe", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "If the user cancels during the trial period after using it for a few days (e.g., 2 days), they won't receive another free trial if they decide to return to the app later.", + }, + propTypes: { + text: "text", + }, + id: "a261ec0b-146d-cd31-8891-4fc42b92c1a0", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: 11, + components: [], + props: { + text: "Start 14 day free trail", + onclick: "navigation", + to: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + id: "983d20ec-34d2-072f-d8d3-43f90ecc8706", + children: [], + }, + ], + }, + { + id: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + name: "Trackingview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 8, + components: [], + id: "142b3d45-3423-46ef-7ce9-06f976af9ab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + children: [], + }, + ], + }, + { + id: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + name: "Workerview", + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 9, + components: [], + id: "839e9f22-a942-d051-cd61-8372738dcab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + children: [], + }, + ], + }, + ], + components: [], + constants: [], + leftPanel: [ + { + type: "FRAGMENT", + name: "Accountview", + order: 5, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "cedf5140-1c20-660c-774d-a6d36bfb223b", + }, + { + type: "FRAGMENT", + name: "Addmaterial", + order: 12, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + { + type: "FRAGMENT", + name: "Costview", + order: 3, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "5d406458-0ce8-beab-c688-eb363661dad1", + }, + { + type: "FRAGMENT", + name: "Dashboardview", + order: 6, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "21324f55-dbc1-a71e-c420-7aed7669de2f", + }, + { + type: "FRAGMENT", + name: "Home", + order: -1, + intent: [], + components: [], + layout: "LinearLayout", + container: "LinearLayout", + id: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + actions: [], + props: { + layout: "LinearLayout", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_LinearLayout", + }, + }, + { + type: "FRAGMENT", + name: "LabortrackingView", + order: 8, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + }, + { + type: "FRAGMENT", + name: "Linealfootsetup", + order: 14, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + }, + { + type: "FRAGMENT", + name: "Materiallist", + order: 13, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "57629038-3779-61e4-9222-413fba948f6d", + }, + { + type: "FRAGMENT", + name: "Materialsetup", + order: 11, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "a763bdbe-c58c-0ed1-110d-00711065d256", + }, + { + type: "FRAGMENT", + name: "Projectview", + order: 2, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "63924326-339a-399f-41cf-092404a69bca", + }, + { + type: "FRAGMENT", + name: "Subcriptionfragment", + order: 10, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "e4621fcf-2b34-dfd9-bd36-556d21401819", + }, + { + type: "FRAGMENT", + name: "Trackingview", + order: 7, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + }, + { + type: "FRAGMENT", + name: "Workerview", + order: 4, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + }, + ], + middlePanel: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 1, + components: [], + id: "e40754ef-7303-e432-4049-dd621424dc48", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cedf5140-1c20-660c-774d-a6d36bfb223b", + children: [], + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "5cedc397-73ca-0247-05e7-f5c32deee49d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "f13a11ee-c0f8-d9e4-f435-eeade06546dc", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Profit Overhead", + }, + propTypes: { + text: "text", + }, + id: "464ba6e4-7c4e-db6f-7af8-b2a742769221", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 3, + components: [], + id: "c0d0f5da-9028-41d6-cb9f-bef20f99a288", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "5d406458-0ce8-beab-c688-eb363661dad1", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 4, + components: [], + id: "77f1c763-cf22-e4c0-ab68-bb6edc2475dd", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "21324f55-dbc1-a71e-c420-7aed7669de2f", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 5, + components: [], + id: "7a5b7443-6f9d-68c0-c878-86af04ce6636", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 6, + components: [], + id: "8e83f3a7-4bd2-3e3c-f458-00a4c7ead46c", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 7, + components: [], + id: "95f48c05-63a7-07e9-820e-2924141a7c0b", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "63924326-339a-399f-41cf-092404a69bca", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 8, + components: [], + id: "142b3d45-3423-46ef-7ce9-06f976af9ab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 9, + components: [], + id: "839e9f22-a942-d051-cd61-8372738dcab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 10, + components: [], + id: "951d1db9-3a90-03f5-9fec-40be63508d25", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Subscription", + }, + propTypes: { + text: "text", + }, + id: "03bafcc0-eff8-418a-de97-55614e63912d", + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "29e2d580-570d-0f0d-8689-f2e0a051d392", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "$45 / Month", + }, + propTypes: { + text: "text", + }, + id: "4999v4boh74v-g7rs3p-910lm0-089xyz-zsrux5qqk05i06j5qe", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "If the user cancels during the trial period after using it for a few days (e.g., 2 days), they won't receive another free trial if they decide to return to the app later.", + }, + propTypes: { + text: "text", + }, + id: "a261ec0b-146d-cd31-8891-4fc42b92c1a0", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: 11, + components: [], + props: { + text: "Start 14 day free trail", + onclick: "navigation", + to: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + id: "983d20ec-34d2-072f-d8d3-43f90ecc8706", + children: [], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 12, + components: [], + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Hourly Rate", + }, + propTypes: { + text: "string", + }, + id: "914b1efe-7a94-6196-128d-ca1f5ec0d445", + parentId: "6c4782a2-5026-7e99-6629-2f9cb56eef29", + parentName: "LinearLayout", + pageId: { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + }, + { + type: "element", + name: "EditText", + icon: "https://cdn-icons-png.flaticon.com/512/84/84380.png", + order: -1, + components: [], + props: { + text: "", + name: "", + }, + propTypes: { + text: "text", + name: "text", + }, + id: "b3b4446e-5383-afcb-24e5-1646c65c2361", + parentId: "6c4782a2-5026-7e99-6629-2f9cb56eef29", + parentName: "LinearLayout", + pageId: { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + }, + ], + id: "6c4782a2-5026-7e99-6629-2f9cb56eef29", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "2f313e36-566f-e504-34d5-8356db95861d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Workers", + }, + propTypes: { + text: "text", + }, + id: "27ff1748-a96a-9384-c3e0-d4d92fb3c018", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "0bc73012-cb2a-1781-7569-841891167249", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "771db74e-37c6-c6cd-c62d-b1197ead23b1", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "+ Add", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "de33bc49-74a1-735c-bc26-4f2dbde093ff", + parentId: "2f313e36-566f-e504-34d5-8356db95861d", + parentName: "RelativeLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 14, + components: [], + id: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "b5480a18-8c78-996e-9717-3174639c8229", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save & Continue", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "945e2d15-15fd-f4d2-a353-4b1157348d5d", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "402b8e07-3b82-9324-8133-36f1783d0243", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "a763bdbe-c58c-0ed1-110d-00711065d256", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "32747828-0ee7-b69d-b9c1-585f02ba0eab", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "62cf8ff1-37d9-1ebf-479f-99c29d0d7700", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: 16, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + pageId: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + id: "993807ed-1158-2d72-23f3-2281e5855e75", + children: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "i0glnmyu8ekz-xn95dj-j9ao2y-8rmcz2-mzjszfbrwvqtiuyjy5", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Unit Cost", + }, + propTypes: { + text: "text", + }, + id: "tt5o08am1y2a-2xqfu6-d6uihy-ifafi6-6pkk450e90vpyzhs1p", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "true", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Cancel", + onclick: "submit", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ldlk8cm79j48-x1lipf-zu7n13-9y2m5r-56qwl7hezv22qmtx0u", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Submit", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "rhygz41im004-vtsqb1-kbbhpd-6sjd53-sjm3cvaqofck1r1ok0", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "930da8c7-1e04-545d-49c1-93338ae5a03c", + pageId: "57629038-3779-61e4-9222-413fba948f6d", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "", + toLeftOf: "", + toRightOf: "parent", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "true", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "3df228c4-b4e6-812a-6851-d7dae0756c38", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + }, + { + type: "layout", + name: "RecyclerView", + component: "DATA_COMPONENT", + icon: "https://cdn-icons-png.flaticon.com/512/4997/4997760.png", + order: -1, + components: [], + props: { + name: "Data", + fields: "id, name, unit_cost", + pass_data: true, + layout_manager: "linear", + columns: "2", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + name: "text", + fields: "text", + pass_data: "boolean", + layout_manager: "options_linear:grid", + columns: "options_1:2:3:4:5:6:7:8", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "084bf25e-2763-3548-dcbf-42f337390e95", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + dataSource: "_materialListTree", + dataSourceName: "Get Material List", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "99e555d4-d5bd-d22c-d852-bc5ced874f63", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add New Lineal foot cost", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ce83daf4-1e5d-6e1f-2f8e-1ef9ed13ac5b", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "0e6bb1f7-63e2-b483-1e16-91236a95bde7", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + ], + rightPanel: { + type: "element", + name: "EditText", + icon: "https://cdn-icons-png.flaticon.com/512/84/84380.png", + order: -1, + components: [], + props: { + text: "Kapil", + name: "namefield", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + name: "text", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "e32b5f6f-a689-4ea9-42ef-5d2bcdfdd9f9", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "RelativeLayout", + }, + selectedComponent: "5cedc397-73ca-0247-05e7-f5c32deee49d", + rightComponentId: "e32b5f6f-a689-4ea9-42ef-5d2bcdfdd9f9", + selectedPageComponent: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + nav: "sideBar", + fragment: [ + { + type: "FRAGMENT", + name: "Accountview", + order: 5, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 1, + components: [], + id: "e40754ef-7303-e432-4049-dd621424dc48", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cedf5140-1c20-660c-774d-a6d36bfb223b", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "cedf5140-1c20-660c-774d-a6d36bfb223b", + }, + { + type: "FRAGMENT", + name: "Addmaterial", + order: 12, + intent: [], + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: 16, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + pageId: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + id: "993807ed-1158-2d72-23f3-2281e5855e75", + children: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "i0glnmyu8ekz-xn95dj-j9ao2y-8rmcz2-mzjszfbrwvqtiuyjy5", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Unit Cost", + }, + propTypes: { + text: "text", + }, + id: "tt5o08am1y2a-2xqfu6-d6uihy-ifafi6-6pkk450e90vpyzhs1p", + parentId: "e204640c-1d1b-4fbc-7884-4d8ee46a8642", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "true", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Cancel", + onclick: "submit", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ldlk8cm79j48-x1lipf-zu7n13-9y2m5r-56qwl7hezv22qmtx0u", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Submit", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "rhygz41im004-vtsqb1-kbbhpd-6sjd53-sjm3cvaqofck1r1ok0", + parentId: "995998a3-91f9-1278-fbf6-1dcdd41cf6f8", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "5cedc397-73ca-0247-05e7-f5c32deee49d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "f13a11ee-c0f8-d9e4-f435-eeade06546dc", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Default Profit Overhead", + }, + propTypes: { + text: "text", + }, + id: "464ba6e4-7c4e-db6f-7af8-b2a742769221", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + ], + }, + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "2f313e36-566f-e504-34d5-8356db95861d", + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Workers", + }, + propTypes: { + text: "text", + }, + id: "27ff1748-a96a-9384-c3e0-d4d92fb3c018", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Name", + }, + propTypes: { + text: "text", + }, + id: "0bc73012-cb2a-1781-7569-841891167249", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Hourly Rate", + }, + propTypes: { + text: "text", + }, + id: "771db74e-37c6-c6cd-c62d-b1197ead23b1", + parentId: "5cedc397-73ca-0247-05e7-f5c32deee49d", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "+ Add", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "de33bc49-74a1-735c-bc26-4f2dbde093ff", + parentId: "2f313e36-566f-e504-34d5-8356db95861d", + parentName: "RelativeLayout", + }, + ], + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 14, + components: [], + id: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + props: { + orientation: "horizontal", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "b5480a18-8c78-996e-9717-3174639c8229", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Save & Continue", + onclick: "submit", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "945e2d15-15fd-f4d2-a353-4b1157348d5d", + parentId: "e1a5833a-7bf8-8a20-a14e-880533c37ace", + parentName: "LinearLayout", + }, + ], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + { + type: "FRAGMENT", + name: "Costview", + order: 3, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 3, + components: [], + id: "c0d0f5da-9028-41d6-cb9f-bef20f99a288", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "5d406458-0ce8-beab-c688-eb363661dad1", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "5d406458-0ce8-beab-c688-eb363661dad1", + }, + { + type: "FRAGMENT", + name: "Dashboardview", + order: 6, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 4, + components: [], + id: "77f1c763-cf22-e4c0-ab68-bb6edc2475dd", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "21324f55-dbc1-a71e-c420-7aed7669de2f", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "21324f55-dbc1-a71e-c420-7aed7669de2f", + }, + { + type: "FRAGMENT", + name: "Home", + order: -1, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 5, + components: [], + id: "7a5b7443-6f9d-68c0-c878-86af04ce6636", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + children: [], + }, + ], + layout: "LinearLayout", + container: "LinearLayout", + id: "9f3966f9-5189-5cc1-2b64-cb01cfa27ed7", + actions: [], + props: { + layout: "LinearLayout", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_LinearLayout", + }, + }, + { + type: "FRAGMENT", + name: "LabortrackingView", + order: 8, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 6, + components: [], + id: "8e83f3a7-4bd2-3e3c-f458-00a4c7ead46c", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "3eccc95d-9b37-e89f-4b9a-1912cc269cb1", + }, + { + type: "FRAGMENT", + name: "Linealfootsetup", + order: 14, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "99e555d4-d5bd-d22c-d852-bc5ced874f63", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add New Lineal foot cost", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "ce83daf4-1e5d-6e1f-2f8e-1ef9ed13ac5b", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "0e6bb1f7-63e2-b483-1e16-91236a95bde7", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "cc620db8-7ec0-eef5-a83d-f7a388b37bf2", + }, + { + type: "FRAGMENT", + name: "Materiallist", + order: 13, + intent: [], + components: [ + { + type: "layout", + name: "RelativeLayout", + icon: "https://cdn-icons-png.flaticon.com/128/1607/1607252.png", + order: -1, + components: [], + props: {}, + propTypes: {}, + childProps: { + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + childPropTypes: { + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "930da8c7-1e04-545d-49c1-93338ae5a03c", + pageId: "57629038-3779-61e4-9222-413fba948f6d", + parentId: "993807ed-1158-2d72-23f3-2281e5855e75", + parentName: "RelativeLayout", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "", + toLeftOf: "", + toRightOf: "parent", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "true", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "3df228c4-b4e6-812a-6851-d7dae0756c38", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + }, + { + type: "layout", + name: "RecyclerView", + component: "DATA_COMPONENT", + icon: "https://cdn-icons-png.flaticon.com/512/4997/4997760.png", + order: -1, + components: [], + props: { + name: "Data", + fields: "id, name, unit_cost", + pass_data: true, + layout_manager: "linear", + columns: "2", + toLeftOf: "", + toRightOf: "", + above: "", + below: "", + centerHorizontal: "", + centerVertical: "", + centerInParent: "", + alignParentTop: "", + alignParentLeft: "", + alignParentRight: "", + alignParentBottom: "", + }, + propTypes: { + name: "text", + fields: "text", + pass_data: "boolean", + layout_manager: "options_linear:grid", + columns: "options_1:2:3:4:5:6:7:8", + toLeftOf: "siblings", + toRightOf: "siblings", + above: "siblings", + below: "siblings", + centerHorizontal: "options_true:false", + centerVertical: "options_true:false", + centerInParent: "options_true:false", + alignParentTop: "options_true:false", + alignParentLeft: "options_true:false", + alignParentRight: "options_true:false", + alignParentBottom: "options_true:false", + }, + id: "084bf25e-2763-3548-dcbf-42f337390e95", + parentId: "930da8c7-1e04-545d-49c1-93338ae5a03c", + parentName: "RelativeLayout", + dataSource: "_materialListTree", + dataSourceName: "Get Material List", + }, + ], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "57629038-3779-61e4-9222-413fba948f6d", + }, + { + type: "FRAGMENT", + name: "Materialsetup", + order: 11, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "402b8e07-3b82-9324-8133-36f1783d0243", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "a763bdbe-c58c-0ed1-110d-00711065d256", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "32747828-0ee7-b69d-b9c1-585f02ba0eab", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "62cf8ff1-37d9-1ebf-479f-99c29d0d7700", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "a763bdbe-c58c-0ed1-110d-00711065d256", + }, + { + type: "FRAGMENT", + name: "Projectview", + order: 2, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 7, + components: [], + id: "95f48c05-63a7-07e9-820e-2924141a7c0b", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "63924326-339a-399f-41cf-092404a69bca", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "63924326-339a-399f-41cf-092404a69bca", + }, + { + type: "FRAGMENT", + name: "Subcriptionfragment", + order: 10, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 10, + components: [], + id: "951d1db9-3a90-03f5-9fec-40be63508d25", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "Subscription", + }, + propTypes: { + text: "text", + }, + id: "03bafcc0-eff8-418a-de97-55614e63912d", + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + }, + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: -1, + components: [], + id: "29e2d580-570d-0f0d-8689-f2e0a051d392", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + parentId: "951d1db9-3a90-03f5-9fec-40be63508d25", + parentName: "LinearLayout", + children: [ + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "$45 / Month", + }, + propTypes: { + text: "text", + }, + id: "4999v4boh74v-g7rs3p-910lm0-089xyz-zsrux5qqk05i06j5qe", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + { + type: "element", + name: "TextView", + icon: "https://cdn-icons-png.flaticon.com/512/32/32329.png", + order: -1, + components: [], + props: { + text: "If the user cancels during the trial period after using it for a few days (e.g., 2 days), they won't receive another free trial if they decide to return to the app later.", + }, + propTypes: { + text: "text", + }, + id: "a261ec0b-146d-cd31-8891-4fc42b92c1a0", + parentId: "29e2d580-570d-0f0d-8689-f2e0a051d392", + parentName: "LinearLayout", + }, + ], + }, + ], + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: 11, + components: [], + props: { + text: "Start 14 day free trail", + onclick: "navigation", + to: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + pageId: "e4621fcf-2b34-dfd9-bd36-556d21401819", + id: "983d20ec-34d2-072f-d8d3-43f90ecc8706", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "e4621fcf-2b34-dfd9-bd36-556d21401819", + }, + { + type: "FRAGMENT", + name: "Trackingview", + order: 7, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 8, + components: [], + id: "142b3d45-3423-46ef-7ce9-06f976af9ab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "6814ce22-3722-c1cd-909c-6dcbb8d55c5a", + }, + { + type: "FRAGMENT", + name: "Workerview", + order: 4, + intent: [], + components: [ + { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 9, + components: [], + id: "839e9f22-a942-d051-cd61-8372738dcab2", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + children: [], + }, + ], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "020f9b50-4247-bfd1-3e07-2e251d0ae286", + }, + ], + activity: [], + copyComponent: { + type: "layout", + name: "LinearLayout", + icon: "https://cdn-icons-png.flaticon.com/512/3094/3094321.png", + order: 15, + components: [], + id: "402b8e07-3b82-9324-8133-36f1783d0243", + props: { + orientation: "vertical", + width: "match_parent", + height: "wrap_content", + }, + propTypes: { + orientation: "options_vertical:horizontal", + width: "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + height: + "options_match_parent:wrap_content:10dp:20dp:30dp:40dp:50dp:100dp", + }, + pageId: "a763bdbe-c58c-0ed1-110d-00711065d256", + children: [ + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Add Material", + onclick: "navigation", + to: "1d84d9cb-f95d-779b-4d3a-86f978680dee", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "32747828-0ee7-b69d-b9c1-585f02ba0eab", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + { + type: "element", + name: "Button", + icon: "https://cdn-icons-png.flaticon.com/512/3305/3305815.png", + order: -1, + components: [], + props: { + text: "Skip", + onclick: "", + }, + propTypes: { + text: "text", + onclick: "action", + to: "skip", + }, + id: "62cf8ff1-37d9-1ebf-479f-99c29d0d7700", + parentId: "402b8e07-3b82-9324-8133-36f1783d0243", + parentName: "LinearLayout", + }, + ], + }, + changedState: 0, + loading: false, + selectedPageId: { + type: "FRAGMENT", + name: "Companysetup", + order: 9, + intent: [], + components: [], + props: { + layout: "", + name: "", + startDestination: false, + actions: [], + }, + propTypes: { + layout: "options_", + }, + id: "f4460074-1148-d24b-7351-eb4f7dc26d4a", + }, + disabledComponent: false, +}; + +const targetId = "f4460074-1148-d24b-7351-eb4f7dc26d4a"; + +const components = androidConfig.middlePanel.filter( + (component) => component.pageId?.id == targetId +); +console.log("components >>", components?.length); diff --git a/postcss.config.js b/postcss.config.ts similarity index 77% rename from postcss.config.js rename to postcss.config.ts index 2aa7205..12a703d 100644 --- a/postcss.config.js +++ b/postcss.config.ts @@ -1,4 +1,4 @@ -export default { +module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, diff --git a/public/_redirects b/public/_redirects new file mode 100644 index 0000000..8e919d6 --- /dev/null +++ b/public/_redirects @@ -0,0 +1 @@ +/* /index.html 200 \ No newline at end of file diff --git a/public/_redirects copy b/public/_redirects copy new file mode 100644 index 0000000..50a4633 --- /dev/null +++ b/public/_redirects copy @@ -0,0 +1 @@ +/* /index.html 200 \ No newline at end of file diff --git a/public/icons/apple-touch-icon-180x180.png b/public/icons/apple-touch-icon-180x180.png new file mode 100644 index 0000000..7af1521 Binary files /dev/null and b/public/icons/apple-touch-icon-180x180.png differ diff --git a/public/icons/favicon.ico b/public/icons/favicon.ico new file mode 100644 index 0000000..99e2bef Binary files /dev/null and b/public/icons/favicon.ico differ diff --git a/public/icons/index.ts b/public/icons/index.ts new file mode 100644 index 0000000..95f0219 --- /dev/null +++ b/public/icons/index.ts @@ -0,0 +1,6 @@ +export { default as AppTouchIconPath } from "./apple-touch-icon-180x180.png"; +export { default as FavIconPath } from "./favicon.ico"; +export { default as MaskableIconPath } from "./maskable-icon-512x512.png"; +export { default as Pwa64x64IconPath } from "./pwa-64x64.png"; +export { default as Pwa192x192IconPath } from "./pwa-192x192.png"; +export { default as Pwa512x512IconPath } from "./pwa-512x512.png"; diff --git a/src/favicon.png b/public/icons/maskable-icon-512x512.png similarity index 100% rename from src/favicon.png rename to public/icons/maskable-icon-512x512.png diff --git a/public/icons/mkd_logo.png b/public/icons/mkd_logo.png new file mode 100644 index 0000000..83b2786 Binary files /dev/null and b/public/icons/mkd_logo.png differ diff --git a/public/icons/pwa-192x192.png b/public/icons/pwa-192x192.png new file mode 100644 index 0000000..76a3868 Binary files /dev/null and b/public/icons/pwa-192x192.png differ diff --git a/public/icons/pwa-512x512.png b/public/icons/pwa-512x512.png new file mode 100644 index 0000000..252277f Binary files /dev/null and b/public/icons/pwa-512x512.png differ diff --git a/public/icons/pwa-64x64.png b/public/icons/pwa-64x64.png new file mode 100644 index 0000000..899eacc Binary files /dev/null and b/public/icons/pwa-64x64.png differ diff --git a/public/images/Wireframes-API-1.png b/public/images/Wireframes-API-1.png new file mode 100644 index 0000000..f0e8d9e Binary files /dev/null and b/public/images/Wireframes-API-1.png differ diff --git a/public/images/Wireframes-API-2.png b/public/images/Wireframes-API-2.png new file mode 100644 index 0000000..cf418c0 Binary files /dev/null and b/public/images/Wireframes-API-2.png differ diff --git a/public/images/addform.png b/public/images/addform.png new file mode 100644 index 0000000..c8bb1c4 Binary files /dev/null and b/public/images/addform.png differ diff --git a/public/images/baas-features-drawer.png b/public/images/baas-features-drawer.png new file mode 100644 index 0000000..79d5e0e Binary files /dev/null and b/public/images/baas-features-drawer.png differ diff --git a/public/images/colorpicker.png b/public/images/colorpicker.png new file mode 100644 index 0000000..a7cba48 Binary files /dev/null and b/public/images/colorpicker.png differ diff --git a/public/images/dashboard-wireframe.png b/public/images/dashboard-wireframe.png new file mode 100644 index 0000000..dde3944 Binary files /dev/null and b/public/images/dashboard-wireframe.png differ diff --git a/public/images/dots-pattern.png b/public/images/dots-pattern.png new file mode 100644 index 0000000..6c3c21e Binary files /dev/null and b/public/images/dots-pattern.png differ diff --git a/public/images/dropdownmenu.png b/public/images/dropdownmenu.png new file mode 100644 index 0000000..7fae204 Binary files /dev/null and b/public/images/dropdownmenu.png differ diff --git a/public/images/editform.png b/public/images/editform.png new file mode 100644 index 0000000..f396bc9 Binary files /dev/null and b/public/images/editform.png differ diff --git a/public/images/feature-preview.png b/public/images/feature-preview.png new file mode 100644 index 0000000..f5039e0 Binary files /dev/null and b/public/images/feature-preview.png differ diff --git a/public/images/graphview.png b/public/images/graphview.png new file mode 100644 index 0000000..f5f4582 Binary files /dev/null and b/public/images/graphview.png differ diff --git a/public/images/scannerview.png b/public/images/scannerview.png new file mode 100644 index 0000000..eed9dc0 Binary files /dev/null and b/public/images/scannerview.png differ diff --git a/public/images/scrollview.png b/public/images/scrollview.png new file mode 100644 index 0000000..1b80780 Binary files /dev/null and b/public/images/scrollview.png differ diff --git a/public/images/searchbar.png b/public/images/searchbar.png new file mode 100644 index 0000000..d4a76e1 Binary files /dev/null and b/public/images/searchbar.png differ diff --git a/public/images/securefield.png b/public/images/securefield.png new file mode 100644 index 0000000..badb41d Binary files /dev/null and b/public/images/securefield.png differ diff --git a/public/mkd_logo.png b/public/mkd_logo.png new file mode 100644 index 0000000..83b2786 Binary files /dev/null and b/public/mkd_logo.png differ diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..2cfc84f --- /dev/null +++ b/src/App.css @@ -0,0 +1,11 @@ +@import "tailwindcss"; +@layer theme, base, components, utilities; +@import "tailwindcss/theme" layer(theme); +@import "tailwindcss/utilities" layer(utilities); + +/* @config "../tailwind.config.js"; */ + +@theme { + --color-primaryBlue: #4f46e5; + --color-primary-light: #4f46e550; +} diff --git a/src/App.tsx b/src/App.tsx index 242878c..654babd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,114 +1,46 @@ -import React, { useState } from 'react'; -import { Sparkles } from 'lucide-react'; -import { ImageUpload } from './components/ImageUpload'; -import { CharacterSelect } from './components/CharacterSelect'; -import { Preview } from './components/Preview'; -import { Character, TransformedImage } from './types'; +import { AuthProvider } from "@/context/Auth"; +import { GlobalProvider } from "@/context/Global"; +// rcovery +import Main from "@/routes/Routes"; +import "@uppy/core/dist/style.css"; +import "@uppy/dashboard/dist/style.css"; +import { BrowserRouter as Router } from "react-router-dom"; +import "react-loading-skeleton/dist/skeleton.css"; +import { loadStripe } from "@stripe/stripe-js"; +import { Elements } from "@stripe/react-stripe-js"; -function App() { - const [selectedImage, setSelectedImage] = useState(null); - const [selectedCharacter, setSelectedCharacter] = useState(null); - const [transformedImage, setTransformedImage] = useState(null); - const [isLoading, setIsLoading] = useState(false); +import "@fontsource/inter"; // Defaults to weight 400 +import "@fontsource/roboto-mono"; // Defaults to weight 400 +import { ErrorBoundary } from "@/components/ErrorBoundary"; - const handleImageSelect = (file: File) => { - setSelectedImage(file); - setTransformedImage(null); - }; +import Hotjar from "@hotjar/browser"; +import { LazyLoad } from "@/components/LazyLoad"; - const handleCharacterSelect = (character: Character) => { - setSelectedCharacter(character); - }; +const siteId = 5128711; +const hotjarVersion = 6; - const handleTransform = async () => { - if (!selectedImage || !selectedCharacter) return; +Hotjar.init(siteId, hotjarVersion); - setIsLoading(true); - - // Simulate transformation with a delay - setTimeout(() => { - const fakeTransformed: TransformedImage = { - original: URL.createObjectURL(selectedImage), - transformed: selectedCharacter.image, - character: selectedCharacter, - timestamp: new Date() - }; - - setTransformedImage(fakeTransformed); - setIsLoading(false); - }, 2000); - }; +const stripePromise = loadStripe( + "pk_test_51Ll5ukBgOlWo0lDUrBhA2W7EX2MwUH9AR5Y3KQoujf7PTQagZAJylWP1UOFbtH4UwxoufZbInwehQppWAq53kmNC00UIKSmebO" +); +function App(): JSX.Element { return ( -
- {/* Header */} -
-
-
-
- -

- Naruto Character Generator -

-
-
-
-
- - {/* Main Content */} -
-
- {/* Step 1: Upload Image */} -
-

- 1. Upload Your Photo -

- -
- - {/* Step 2: Select Character */} - {selectedImage && ( -
-

- 2. Choose Your Character -

- -
- )} - - {/* Transform Button */} - {selectedImage && selectedCharacter && ( -
- -
- )} - - {/* Preview */} - {transformedImage && ( -
- -
- )} -
-
-
+ + + + Error}> + + +
+ + + + + + ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/assets/files/Baas V5.postman_collection.json b/src/assets/files/Baas V5.postman_collection.json new file mode 100644 index 0000000..bb3f8fb --- /dev/null +++ b/src/assets/files/Baas V5.postman_collection.json @@ -0,0 +1,2068 @@ +{ + "info": { + "_postman_id": "98d685c0-bc15-43bc-9026-48896dd7bbe6", + "name": "Baas V5", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "19666283", + "_collection_link": "https://grey-water-247011.postman.co/workspace/Baas~5df85c16-5ad5-4de2-a343-af959ce7fc58/collection/19666283-98d685c0-bc15-43bc-9026-48896dd7bbe6?action=share&source=collection_link&creator=19666283" + }, + "item": [ + { + "name": "Wireframe", + "item": [ + { + "name": "Project", + "item": [ + { + "name": "Treeql Get One", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Many", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=user&include=user_id,type,user.status,user.email,user.id&exclude=token,user.password", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "user" + }, + { + "key": "include", + "value": "user_id,type,user.status,user.email,user.id" + }, + { + "key": "exclude", + "value": "token,user.password" + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Paginate", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table?page=1&exclude=password,tokens.token&filter=status,gt,0", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "page", + "value": "1" + }, + { + "key": "exclude", + "value": "password,tokens.token" + }, + { + "key": "include", + "value": "id,email,tokens.id", + "disabled": true + }, + { + "key": "filter", + "value": "status,gt,0" + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Create", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"bootstrap app\",\r\n \"slug\": \"bootstrap\",\r\n \"hostname\": \"bootstrap.manaknightdigital.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "response": [ + { + "name": "Treeql Create", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"bootstrap app\",\r\n \"slug\": \"bootstrap\",\r\n \"hostname\": \"bootstrap.manaknightdigital.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "118" + }, + { + "key": "ETag", + "value": "W/\"76-/5m6MiGkdAVxj5e4siONR0gP0KY\"" + }, + { + "key": "Date", + "value": "Sat, 15 Feb 2025 07:41:58 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"status\": 200,\n \"model\": {\n \"name\": \"bootstrap app\",\n \"slug\": \"bootstrap\",\n \"hostname\": \"bootstrap.manaknightdigital.com\",\n \"id\": 1\n }\n}" + } + ] + }, + { + "name": "Treeql Update", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"config\": \"{}\",\r\n \"status\": 1\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Archive Project", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": 0\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Delete", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Deployment", + "item": [ + { + "name": "Find Domain", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain?subdomain=core", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + }, + { + "key": "subdomain", + "value": "core" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Domain", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"subdomain\": \"coretest\",\r\n \"ip\": \"23.29.118.76\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ] + } + }, + "response": [ + { + "name": "Create Domain", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"subdomain\": \"coretest\",\r\n \"ip\": \"23.29.118.76\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "169" + }, + { + "key": "ETag", + "value": "W/\"a9-KwAzLClYF/pB0QnMWlqvfqG1uBs\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:12:21 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 1769701930,\n \"type\": \"A\",\n \"name\": \"coretest\",\n \"data\": \"23.29.118.76\",\n \"priority\": null,\n \"port\": null,\n \"ttl\": 3600,\n \"weight\": null,\n \"flags\": null,\n \"tag\": null\n }\n}" + } + ] + }, + { + "name": "Delete Domain", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain", + ":id" + ], + "variable": [ + { + "key": "id", + "value": "1769701930" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Repo", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + }, + { + "name": "Get Repository Branches", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "response": [ + { + "name": "Get Repo Branches", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "1523" + }, + { + "key": "ETag", + "value": "W/\"5f3-+FMd33lZuRj587/P+3+9IUrrsdI\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:26:15 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"list\": [\n {\n \"name\": \"dev\",\n \"commit\": {\n \"id\": \"bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"message\": \"Initial commit\\n\",\n \"url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend/commit/bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"author\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"committer\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"verification\": {\n \"verified\": false,\n \"reason\": \"gpg.error.not_signed_commit\",\n \"signature\": \"\",\n \"signer\": null,\n \"payload\": \"\"\n },\n \"timestamp\": \"2025-02-19T22:20:46Z\",\n \"added\": null,\n \"removed\": null,\n \"modified\": null\n },\n \"protected\": false,\n \"required_approvals\": 0,\n \"enable_status_check\": false,\n \"status_check_contexts\": [],\n \"user_can_push\": true,\n \"user_can_merge\": true,\n \"effective_branch_protection_name\": \"\"\n },\n {\n \"name\": \"master\",\n \"commit\": {\n \"id\": \"bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"message\": \"Initial commit\\n\",\n \"url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend/commit/bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"author\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"committer\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"verification\": {\n \"verified\": false,\n \"reason\": \"gpg.error.not_signed_commit\",\n \"signature\": \"\",\n \"signer\": null,\n \"payload\": \"\"\n },\n \"timestamp\": \"2025-02-19T22:20:46Z\",\n \"added\": null,\n \"removed\": null,\n \"modified\": null\n },\n \"protected\": false,\n \"required_approvals\": 0,\n \"enable_status_check\": false,\n \"status_check_contexts\": [],\n \"user_can_push\": true,\n \"user_can_merge\": true,\n \"effective_branch_protection_name\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create Repo Branch", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"branch\": \"dev\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Jenkins Frontend Job", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"project\": \"coretest\",\r\n \"branch\": \"master\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/job/frontend", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "job", + "frontend" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + }, + { + "name": "Create Jenkins Backend Job", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"project\": \"coretest\",\r\n \"branch\": \"master\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/job/backend", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "job", + "backend" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + } + ] + }, + { + "name": "Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"adminsuper@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/login", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "login" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoic3VwZXJfYWRtaW4iLCJpYXQiOjE3Mzk2MDQ1NDcsImV4cCI6MTc0MDIwOTM0N30.9mELd9NnKoU1ycsEo5vE8w0Zh5nlkwzQWSOBSdomVbg", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Register", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp43@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"first_name\": \"Member\",\r\n \"last_name\": \"User\",\r\n \"phone\": \"\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/register", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "register" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"adminsuper@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"role\": \"super_admin\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/login", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "login" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + } + ] + } + }, + "response": [] + }, + { + "name": "Refresh Token", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/refresh_token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "refresh_token" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Reset", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"code\": \"37078626\",\r\n \"password\": \"a123456\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/reset", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "reset" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Email", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Password", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Verify account", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Forgot", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/refresh_token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "refresh_token" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get One", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=tokens&exclude=tokens.token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "tokens" + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "user" + }, + { + "key": "id", + "value": "6" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Many", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=user&include=user_id,type,user.status,user.email,user.id&exclude=token,user.password", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "user" + }, + { + "key": "include", + "value": "user_id,type,user.status,user.email,user.id" + }, + { + "key": "exclude", + "value": "token,user.password" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "tokens" + }, + { + "key": "id", + "value": "6,18" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Paginate", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table?join=tokens&page=1,5&exclude=password,tokens.token&filter=id,gt,16", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "query": [ + { + "key": "join", + "value": "tokens" + }, + { + "key": "page", + "value": "1,5" + }, + { + "key": "exclude", + "value": "password,tokens.token" + }, + { + "key": "include", + "value": "id,email,tokens.id", + "disabled": true + }, + { + "key": "filter", + "value": "id,gt,16" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "user" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Create", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Emmy\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Update", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Delete", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:5172", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/src/assets/files/___Baas V5.postman_collection b/src/assets/files/___Baas V5.postman_collection new file mode 100644 index 0000000..889af62 --- /dev/null +++ b/src/assets/files/___Baas V5.postman_collection @@ -0,0 +1,2168 @@ +{ + "info": { + "_postman_id": "98d685c0-bc15-43bc-9026-48896dd7bbe6", + "name": "Baas V5", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "19666283", + "_collection_link": "https://grey-water-247011.postman.co/workspace/Baas~5df85c16-5ad5-4de2-a343-af959ce7fc58/collection/19666283-98d685c0-bc15-43bc-9026-48896dd7bbe6?action=share&source=collection_link&creator=19666283" + }, + "item": [ + { + "name": "Wireframe", + "item": [ + { + "name": "Project", + "item": [ + { + "name": "Treeql Get One", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Many", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=user&include=user_id,type,user.status,user.email,user.id&exclude=token,user.password", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "user" + }, + { + "key": "include", + "value": "user_id,type,user.status,user.email,user.id" + }, + { + "key": "exclude", + "value": "token,user.password" + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Paginate", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table?page=1&exclude=password,tokens.token&filter=status,gt,0", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "page", + "value": "1" + }, + { + "key": "exclude", + "value": "password,tokens.token" + }, + { + "key": "include", + "value": "id,email,tokens.id", + "disabled": true + }, + { + "key": "filter", + "value": "status,gt,0" + } + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Create", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"bootstrap app\",\r\n \"slug\": \"bootstrap\",\r\n \"hostname\": \"bootstrap.manaknightdigital.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "response": [ + { + "name": "Treeql Create", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"bootstrap app\",\r\n \"slug\": \"bootstrap\",\r\n \"hostname\": \"bootstrap.manaknightdigital.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "118" + }, + { + "key": "ETag", + "value": "W/\"76-/5m6MiGkdAVxj5e4siONR0gP0KY\"" + }, + { + "key": "Date", + "value": "Sat, 15 Feb 2025 07:41:58 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"status\": 200,\n \"model\": {\n \"name\": \"bootstrap app\",\n \"slug\": \"bootstrap\",\n \"hostname\": \"bootstrap.manaknightdigital.com\",\n \"id\": 1\n }\n}" + } + ] + }, + { + "name": "Treeql Update", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"config\": \"{}\",\r\n \"status\": 1\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Archive Project", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": 0\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "project" + }, + { + "key": "id", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Delete", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Deployment", + "item": [ + { + "name": "Find Domain", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain?subdomain=core", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + }, + { + "key": "subdomain", + "value": "core" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Domain", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"subdomain\": \"coretest\",\r\n \"ip\": \"23.29.118.76\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ] + } + }, + "response": [ + { + "name": "Create Domain", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"subdomain\": \"coretest\",\r\n \"ip\": \"23.29.118.76\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain" + ], + "query": [ + { + "key": "join", + "value": "tokens", + "disabled": true + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "169" + }, + { + "key": "ETag", + "value": "W/\"a9-KwAzLClYF/pB0QnMWlqvfqG1uBs\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:12:21 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 1769701930,\n \"type\": \"A\",\n \"name\": \"coretest\",\n \"data\": \"23.29.118.76\",\n \"priority\": null,\n \"port\": null,\n \"ttl\": 3600,\n \"weight\": null,\n \"flags\": null,\n \"tag\": null\n }\n}" + } + ] + }, + { + "name": "Delete Domain", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/domain/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "domain", + ":id" + ], + "variable": [ + { + "key": "id", + "value": "1769701930" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Repo", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + }, + { + "name": "Get Repository Branches", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "response": [ + { + "name": "Get Repo Branches", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "1523" + }, + { + "key": "ETag", + "value": "W/\"5f3-+FMd33lZuRj587/P+3+9IUrrsdI\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:26:15 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"list\": [\n {\n \"name\": \"dev\",\n \"commit\": {\n \"id\": \"bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"message\": \"Initial commit\\n\",\n \"url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend/commit/bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"author\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"committer\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"verification\": {\n \"verified\": false,\n \"reason\": \"gpg.error.not_signed_commit\",\n \"signature\": \"\",\n \"signer\": null,\n \"payload\": \"\"\n },\n \"timestamp\": \"2025-02-19T22:20:46Z\",\n \"added\": null,\n \"removed\": null,\n \"modified\": null\n },\n \"protected\": false,\n \"required_approvals\": 0,\n \"enable_status_check\": false,\n \"status_check_contexts\": [],\n \"user_can_push\": true,\n \"user_can_merge\": true,\n \"effective_branch_protection_name\": \"\"\n },\n {\n \"name\": \"master\",\n \"commit\": {\n \"id\": \"bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"message\": \"Initial commit\\n\",\n \"url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend/commit/bbc762b0c840b7cf0f6a4b0f257cc85d17844049\",\n \"author\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"committer\": {\n \"name\": \"manaknight\",\n \"email\": \"info@mkdlabs.com\",\n \"username\": \"manaknight\"\n },\n \"verification\": {\n \"verified\": false,\n \"reason\": \"gpg.error.not_signed_commit\",\n \"signature\": \"\",\n \"signer\": null,\n \"payload\": \"\"\n },\n \"timestamp\": \"2025-02-19T22:20:46Z\",\n \"added\": null,\n \"removed\": null,\n \"modified\": null\n },\n \"protected\": false,\n \"required_approvals\": 0,\n \"enable_status_check\": false,\n \"status_check_contexts\": [],\n \"user_can_push\": true,\n \"user_can_merge\": true,\n \"effective_branch_protection_name\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create Repo Branch", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"branch\": \"dev\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository/:name/branches", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository", + ":name", + "branches" + ], + "variable": [ + { + "key": "name", + "value": "coretest_frontend" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Jenkins Frontend Job", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"project\": \"coretest\",\r\n \"branch\": \"master\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/job/frontend", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "job", + "frontend" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + }, + { + "name": "Create Jenkins Backend Job", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"project\": \"coretest\",\r\n \"branch\": \"master\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/job/backend", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "job", + "backend" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + }, + { + "name": "Setup Backend", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"project\": \"coretest\",\r\n \"config\": \"{ \\\"settings\\\": { \\\"globalKey\\\": \\\"key_1739600667919_juc6ujk6b\\\", \\\"databaseType\\\": \\\"mysql\\\", \\\"authType\\\": \\\"session\\\", \\\"timezone\\\": \\\"UTC\\\", \\\"dbHost\\\": \\\"localhost\\\", \\\"dbPort\\\": \\\"3306\\\", \\\"dbUser\\\": \\\"root\\\", \\\"dbPassword\\\": \\\"root\\\", \\\"dbName\\\": \\\"baas_db\\\", \\\"id\\\": \\\"project_1739600667919_p8rer24k1\\\", \\\"isPWA\\\": false, \\\"isMultiTenant\\\": false, \\\"model_namespace\\\": \\\"core\\\", \\\"payment_option\\\": \\\"none\\\" }, \\\"models\\\": [ { \\\"id\\\": \\\"model_1739601142401_peeb7di4e\\\", \\\"name\\\": \\\"user\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"email\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required,email\\\" }, { \\\"name\\\": \\\"password\\\", \\\"type\\\": \\\"password\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"login_type\\\", \\\"type\\\": \\\"mapping\\\", \\\"mapping\\\": \\\"0:Regular,1:Google,2:Microsoft,3:Apple,4:Twitter,5:Facebook\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"required,enum:0,1,2,3,4,5\\\" }, { \\\"name\\\": \\\"role_id\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"data\\\", \\\"type\\\": \\\"json\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"mapping\\\", \\\"mapping\\\": \\\"0:Active,1:Inactive,2:Suspend\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"required,enum:0,1,2\\\" }, { \\\"name\\\": \\\"verify\\\", \\\"type\\\": \\\"boolean\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"two_factor_authentication\\\", \\\"type\\\": \\\"boolean\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"company_id\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"created_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"CURRENT_TIMESTAMP\\\", \\\"validation\\\": \\\"date\\\" } ] }, { \\\"id\\\": \\\"model_1739601142401_dxr5wrxjj\\\", \\\"name\\\": \\\"preference\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"first_name\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"last_name\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"phone\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"photo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"user_id\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" } ] }, { \\\"id\\\": \\\"model_1739601142401_ck9j7733v\\\", \\\"name\\\": \\\"tokens\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"user_id\\\", \\\"type\\\": \\\"foreign key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"token\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"code\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"type\\\", \\\"type\\\": \\\"mapping\\\", \\\"mapping\\\": \\\"0:Access,1:Refresh,2:Reset,3:Verify,4:Magic\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"required,enum:0,1,2,3,4\\\" }, { \\\"name\\\": \\\"data\\\", \\\"type\\\": \\\"json\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"mapping\\\", \\\"mapping\\\": \\\"0:Inactive,1:Active\\\", \\\"defaultValue\\\": \\\"1\\\", \\\"validation\\\": \\\"required,enum:0,1\\\" }, { \\\"name\\\": \\\"created_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"CURRENT_TIMESTAMP\\\", \\\"validation\\\": \\\"date\\\" }, { \\\"name\\\": \\\"updated_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"CURRENT_TIMESTAMP\\\", \\\"validation\\\": \\\"date\\\" }, { \\\"name\\\": \\\"expired_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"date\\\" } ] }, { \\\"id\\\": \\\"model_1739601142401_5hcxwpay0\\\", \\\"name\\\": \\\"job\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"task\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"arguments\\\", \\\"type\\\": \\\"json\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"time_interval\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"once\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"retries\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"1\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"mapping\\\", \\\"mapping\\\": \\\"0:Pending,1:Failed,2:Processing,3:Completed\\\", \\\"defaultValue\\\": \\\"0\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"created_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"CURRENT_TIMESTAMP\\\", \\\"validation\\\": \\\"date\\\" }, { \\\"name\\\": \\\"updated_at\\\", \\\"type\\\": \\\"timestamp\\\", \\\"defaultValue\\\": \\\"CURRENT_TIMESTAMP\\\", \\\"validation\\\": \\\"date\\\" } ] }, { \\\"id\\\": \\\"model_1739601312991_abhjsog49\\\", \\\"name\\\": \\\"project\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {} }, { \\\"name\\\": \\\"name\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"slug\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"hostname\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"config\\\", \\\"type\\\": \\\"long text\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" } ], \\\"relations\\\": [] }, { \\\"id\\\": \\\"model_1739601482821_45p1vmose\\\", \\\"name\\\": \\\"deployment\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"primary key\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {} }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"project_id\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"domain_id\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"android_repo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"ios_repo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"required\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"ds_repo\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"branch\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"defaultValue\\\": \\\"\\\", \\\"validation\\\": \\\"\\\", \\\"validationOptions\\\": {}, \\\"relation\\\": \\\"\\\" } ], \\\"relations\\\": [] } ], \\\"routes\\\": [ { \\\"id\\\": \\\"route_1739601480588_imqa2fmna\\\", \\\"name\\\": \\\"Get All project\\\", \\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/project\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601480588\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Get All project\\\", \\\"path\\\": \\\"/api/project\\\", \\\"method\\\": \\\"GET\\\" } }, { \\\"id\\\": \\\"auth_node_1739601480588\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_find_node_1739601480588\\\", \\\"type\\\": \\\"db-find\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Find\\\", \\\"model\\\": \\\"project\\\", \\\"operation\\\": \\\"findMany\\\", \\\"query\\\": \\\"SELECT * FROM project\\\", \\\"resultVar\\\": \\\"projectResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601480588\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601480588\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" }, { \\\"name\\\": \\\"name\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"slug\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"hostname\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"config\\\", \\\"type\\\": \\\"string\\\" } ], \\\"resultVar\\\": \\\"projectResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601480588\\\", \\\"source\\\": \\\"url_node_1739601480588\\\", \\\"target\\\": \\\"auth_node_1739601480588\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601480588\\\", \\\"source\\\": \\\"auth_node_1739601480588\\\", \\\"target\\\": \\\"db_find_node_1739601480588\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601480588\\\", \\\"source\\\": \\\"db_find_node_1739601480588\\\", \\\"target\\\": \\\"logic_node_1739601480588\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601480588\\\", \\\"source\\\": \\\"logic_node_1739601480588\\\", \\\"target\\\": \\\"output_node_1739601480588\\\" } ] } }, { \\\"id\\\": \\\"route_1739601480588_6vj8q5gku\\\", \\\"name\\\": \\\"Get One project\\\", \\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/project/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601480588_1\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Get One project\\\", \\\"path\\\": \\\"/api/project/:id\\\", \\\"method\\\": \\\"GET\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601480588_1\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_query_node_1739601480588_1\\\", \\\"type\\\": \\\"db-query\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Find\\\", \\\"model\\\": \\\"project\\\", \\\"operation\\\": \\\"findOne\\\", \\\"query\\\": \\\"SELECT * FROM project WHERE id=id\\\", \\\"resultVar\\\": \\\"projectOneResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601480588_1\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601480588_1\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" }, { \\\"name\\\": \\\"name\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"slug\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"hostname\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"config\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" } ], \\\"resultVar\\\": \\\"projectOneResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601480588_1\\\", \\\"source\\\": \\\"url_node_1739601480588_1\\\", \\\"target\\\": \\\"auth_node_1739601480588_1\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601480588_1\\\", \\\"source\\\": \\\"auth_node_1739601480588_1\\\", \\\"target\\\": \\\"db_query_node_1739601480588_1\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601480588_1\\\", \\\"source\\\": \\\"db_query_node_1739601480588_1\\\", \\\"target\\\": \\\"logic_node_1739601480588_1\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601480588_1\\\", \\\"source\\\": \\\"logic_node_1739601480588_1\\\", \\\"target\\\": \\\"output_node_1739601480588_1\\\" } ] } }, { \\\"id\\\": \\\"route_1739601480589_cnbdo5srf\\\", \\\"name\\\": \\\"Create project\\\", \\\"method\\\": \\\"POST\\\", \\\"url\\\": \\\"/api/project\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601480588_3\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Create project\\\", \\\"path\\\": \\\"/api/project\\\", \\\"method\\\": \\\"POST\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"name\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"slug\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"hostname\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"config\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601480588_3\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_insert_node_1739601480588_3\\\", \\\"type\\\": \\\"db-insert\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Insert\\\", \\\"model\\\": \\\"project\\\", \\\"operation\\\": \\\"create\\\", \\\"query\\\": \\\"INSERT INTO project (name, slug, hostname, config) VALUES (:name, :slug, :hostname, :config)\\\", \\\"resultVar\\\": \\\"projectCreateResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601480588_3\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601480588_3\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" } ], \\\"resultVar\\\": \\\"projectCreateResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601480588_3\\\", \\\"source\\\": \\\"url_node_1739601480588_3\\\", \\\"target\\\": \\\"auth_node_1739601480588_3\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601480588_3\\\", \\\"source\\\": \\\"auth_node_1739601480588_3\\\", \\\"target\\\": \\\"db_insert_node_1739601480588_3\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601480588_3\\\", \\\"source\\\": \\\"db_insert_node_1739601480588_3\\\", \\\"target\\\": \\\"logic_node_1739601480588_3\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601480588_3\\\", \\\"source\\\": \\\"logic_node_1739601480588_3\\\", \\\"target\\\": \\\"output_node_1739601480588_3\\\" } ] } }, { \\\"id\\\": \\\"route_1739601480589_dpkzn6wcd\\\", \\\"name\\\": \\\"Update project\\\", \\\"method\\\": \\\"PUT\\\", \\\"url\\\": \\\"/api/project/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601480588_4\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Update project\\\", \\\"path\\\": \\\"/api/project/:id\\\", \\\"method\\\": \\\"PUT\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ], \\\"fields\\\": [ { \\\"name\\\": \\\"name\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"slug\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"hostname\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"config\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601480588_4\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_update_node_1739601480588_4\\\", \\\"type\\\": \\\"db-update\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Update\\\", \\\"model\\\": \\\"project\\\", \\\"operation\\\": \\\"update\\\", \\\"idField\\\": \\\"id\\\", \\\"query\\\": \\\"UPDATE project SET name=:name, slug=:slug, hostname=:hostname, config=:config WHERE id=:id\\\", \\\"resultVar\\\": \\\"projectUpdateResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601480588_4\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601480588_4\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" } ], \\\"resultVar\\\": \\\"projectUpdateResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601480588_4\\\", \\\"source\\\": \\\"url_node_1739601480588_4\\\", \\\"target\\\": \\\"auth_node_1739601480588_4\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601480588_4\\\", \\\"source\\\": \\\"auth_node_1739601480588_4\\\", \\\"target\\\": \\\"db_update_node_1739601480588_4\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601480588_4\\\", \\\"source\\\": \\\"db_update_node_1739601480588_4\\\", \\\"target\\\": \\\"logic_node_1739601480588_4\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601480588_4\\\", \\\"source\\\": \\\"logic_node_1739601480588_4\\\", \\\"target\\\": \\\"output_node_1739601480588_4\\\" } ] } }, { \\\"id\\\": \\\"route_1739601480589_ybpnxdhva\\\", \\\"name\\\": \\\"Delete One project\\\", \\\"method\\\": \\\"DELETE\\\", \\\"url\\\": \\\"/api/project/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601480588_2\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Delete One project\\\", \\\"path\\\": \\\"/api/project/:id\\\", \\\"method\\\": \\\"DELETE\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601480588_2\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_delete_node_1739601480588_2\\\", \\\"type\\\": \\\"db-delete\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Delete\\\", \\\"model\\\": \\\"project\\\", \\\"operation\\\": \\\"delete\\\", \\\"query\\\": \\\"DELETE FROM project WHERE id=id\\\", \\\"resultVar\\\": \\\"projectDeleteResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601480588_2\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601480588_2\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"integer\\\" } ], \\\"statusCode\\\": 200, \\\"resultVar\\\": \\\"projectDeleteResult\\\" } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601480588_2\\\", \\\"source\\\": \\\"url_node_1739601480588_2\\\", \\\"target\\\": \\\"auth_node_1739601480588_2\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601480588_2\\\", \\\"source\\\": \\\"auth_node_1739601480588_2\\\", \\\"target\\\": \\\"db_delete_node_1739601480588_2\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601480588_2\\\", \\\"source\\\": \\\"db_delete_node_1739601480588_2\\\", \\\"target\\\": \\\"logic_node_1739601480588_2\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601480588_2\\\", \\\"source\\\": \\\"logic_node_1739601480588_2\\\", \\\"target\\\": \\\"output_node_1739601480588_2\\\" } ] } }, { \\\"id\\\": \\\"route_1739601748474_b8q02921w\\\", \\\"name\\\": \\\"Get All deployment\\\", \\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/deployment\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601748474\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Get All deployment\\\", \\\"path\\\": \\\"/api/deployment\\\", \\\"method\\\": \\\"GET\\\" } }, { \\\"id\\\": \\\"auth_node_1739601748474\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_find_node_1739601748474\\\", \\\"type\\\": \\\"db-find\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Find\\\", \\\"model\\\": \\\"deployment\\\", \\\"operation\\\": \\\"findMany\\\", \\\"query\\\": \\\"SELECT * FROM deployment\\\", \\\"resultVar\\\": \\\"deploymentResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601748474\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601748474\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\" }, { \\\"name\\\": \\\"project_id\\\", \\\"type\\\": \\\"integer\\\" }, { \\\"name\\\": \\\"domain_id\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"frontend_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"backend_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"android_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"ios_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"ds_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"branch\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"frontend_deployed\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"backend_deployed\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\" } ], \\\"resultVar\\\": \\\"deploymentResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601748474\\\", \\\"source\\\": \\\"url_node_1739601748474\\\", \\\"target\\\": \\\"auth_node_1739601748474\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601748474\\\", \\\"source\\\": \\\"auth_node_1739601748474\\\", \\\"target\\\": \\\"db_find_node_1739601748474\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601748474\\\", \\\"source\\\": \\\"db_find_node_1739601748474\\\", \\\"target\\\": \\\"logic_node_1739601748474\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601748474\\\", \\\"source\\\": \\\"logic_node_1739601748474\\\", \\\"target\\\": \\\"output_node_1739601748474\\\" } ] } }, { \\\"id\\\": \\\"route_1739601748474_refvqst89\\\", \\\"name\\\": \\\"Get One deployment\\\", \\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/deployment/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601748474_1\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Get One deployment\\\", \\\"path\\\": \\\"/api/deployment/:id\\\", \\\"method\\\": \\\"GET\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601748474_1\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_query_node_1739601748474_1\\\", \\\"type\\\": \\\"db-query\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Find\\\", \\\"model\\\": \\\"deployment\\\", \\\"operation\\\": \\\"findOne\\\", \\\"query\\\": \\\"SELECT * FROM deployment WHERE id=id\\\", \\\"resultVar\\\": \\\"deploymentOneResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601748474_1\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601748474_1\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\" }, { \\\"name\\\": \\\"project_id\\\", \\\"type\\\": \\\"integer\\\" }, { \\\"name\\\": \\\"domain_id\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"frontend_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"backend_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"android_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"ios_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"ds_repo\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"branch\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"frontend_deployed\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"backend_deployed\\\", \\\"type\\\": \\\"string\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\" }, { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" } ], \\\"resultVar\\\": \\\"deploymentOneResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601748474_1\\\", \\\"source\\\": \\\"url_node_1739601748474_1\\\", \\\"target\\\": \\\"auth_node_1739601748474_1\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601748474_1\\\", \\\"source\\\": \\\"auth_node_1739601748474_1\\\", \\\"target\\\": \\\"db_query_node_1739601748474_1\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601748474_1\\\", \\\"source\\\": \\\"db_query_node_1739601748474_1\\\", \\\"target\\\": \\\"logic_node_1739601748474_1\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601748474_1\\\", \\\"source\\\": \\\"logic_node_1739601748474_1\\\", \\\"target\\\": \\\"output_node_1739601748474_1\\\" } ] } }, { \\\"id\\\": \\\"route_1739601748474_26to8u949\\\", \\\"name\\\": \\\"Create deployment\\\", \\\"method\\\": \\\"POST\\\", \\\"url\\\": \\\"/api/deployment\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601748474_3\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Create deployment\\\", \\\"path\\\": \\\"/api/deployment\\\", \\\"method\\\": \\\"POST\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"project_id\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"domain_id\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"android_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"ios_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"ds_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"branch\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601748474_3\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_insert_node_1739601748474_3\\\", \\\"type\\\": \\\"db-insert\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Insert\\\", \\\"model\\\": \\\"deployment\\\", \\\"operation\\\": \\\"create\\\", \\\"query\\\": \\\"INSERT INTO deployment (status, project_id, domain_id, frontend_repo, backend_repo, android_repo, ios_repo, ds_repo, branch, frontend_deployed, backend_deployed, status) VALUES (:status, :project_id, :domain_id, :frontend_repo, :backend_repo, :android_repo, :ios_repo, :ds_repo, :branch, :frontend_deployed, :backend_deployed, :status)\\\", \\\"resultVar\\\": \\\"deploymentCreateResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601748474_3\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601748474_3\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" } ], \\\"resultVar\\\": \\\"deploymentCreateResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601748474_3\\\", \\\"source\\\": \\\"url_node_1739601748474_3\\\", \\\"target\\\": \\\"auth_node_1739601748474_3\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601748474_3\\\", \\\"source\\\": \\\"auth_node_1739601748474_3\\\", \\\"target\\\": \\\"db_insert_node_1739601748474_3\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601748474_3\\\", \\\"source\\\": \\\"db_insert_node_1739601748474_3\\\", \\\"target\\\": \\\"logic_node_1739601748474_3\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601748474_3\\\", \\\"source\\\": \\\"logic_node_1739601748474_3\\\", \\\"target\\\": \\\"output_node_1739601748474_3\\\" } ] } }, { \\\"id\\\": \\\"route_1739601748475_v50env6r7\\\", \\\"name\\\": \\\"Update deployment\\\", \\\"method\\\": \\\"PUT\\\", \\\"url\\\": \\\"/api/deployment/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601748474_4\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Update deployment\\\", \\\"path\\\": \\\"/api/deployment/:id\\\", \\\"method\\\": \\\"PUT\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ], \\\"fields\\\": [ { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"project_id\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"domain_id\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"android_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"ios_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"required\\\" }, { \\\"name\\\": \\\"ds_repo\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"branch\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"frontend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"backend_deployed\\\", \\\"type\\\": \\\"string\\\", \\\"validation\\\": \\\"\\\" }, { \\\"name\\\": \\\"status\\\", \\\"type\\\": \\\"integer\\\", \\\"validation\\\": \\\"\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601748474_4\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_update_node_1739601748474_4\\\", \\\"type\\\": \\\"db-update\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Update\\\", \\\"model\\\": \\\"deployment\\\", \\\"operation\\\": \\\"update\\\", \\\"idField\\\": \\\"id\\\", \\\"query\\\": \\\"UPDATE deployment SET status=:status, project_id=:project_id, domain_id=:domain_id, frontend_repo=:frontend_repo, backend_repo=:backend_repo, android_repo=:android_repo, ios_repo=:ios_repo, ds_repo=:ds_repo, branch=:branch, frontend_deployed=:frontend_deployed, backend_deployed=:backend_deployed, status=:status WHERE id=:id\\\", \\\"resultVar\\\": \\\"deploymentUpdateResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601748474_4\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601748474_4\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\" } ], \\\"resultVar\\\": \\\"deploymentUpdateResult\\\", \\\"statusCode\\\": 200 } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601748474_4\\\", \\\"source\\\": \\\"url_node_1739601748474_4\\\", \\\"target\\\": \\\"auth_node_1739601748474_4\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601748474_4\\\", \\\"source\\\": \\\"auth_node_1739601748474_4\\\", \\\"target\\\": \\\"db_update_node_1739601748474_4\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601748474_4\\\", \\\"source\\\": \\\"db_update_node_1739601748474_4\\\", \\\"target\\\": \\\"logic_node_1739601748474_4\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601748474_4\\\", \\\"source\\\": \\\"logic_node_1739601748474_4\\\", \\\"target\\\": \\\"output_node_1739601748474_4\\\" } ] } }, { \\\"id\\\": \\\"route_1739601748474_x8wfmbmya\\\", \\\"name\\\": \\\"Delete One deployment\\\", \\\"method\\\": \\\"DELETE\\\", \\\"url\\\": \\\"/api/deployment/:id\\\", \\\"flowData\\\": { \\\"nodes\\\": [ { \\\"id\\\": \\\"url_node_1739601748474_2\\\", \\\"type\\\": \\\"url\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 100 }, \\\"data\\\": { \\\"label\\\": \\\"Url\\\", \\\"apiname\\\": \\\"Delete One deployment\\\", \\\"path\\\": \\\"/api/deployment/:id\\\", \\\"method\\\": \\\"DELETE\\\", \\\"queryFields\\\": [ { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"number\\\", \\\"validation\\\": \\\"required\\\" } ] } }, { \\\"id\\\": \\\"auth_node_1739601748474_2\\\", \\\"type\\\": \\\"auth\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 200 }, \\\"data\\\": { \\\"label\\\": \\\"Auth\\\", \\\"authType\\\": \\\"none\\\" } }, { \\\"id\\\": \\\"db_delete_node_1739601748474_2\\\", \\\"type\\\": \\\"db-delete\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 300 }, \\\"data\\\": { \\\"label\\\": \\\"Database Delete\\\", \\\"model\\\": \\\"deployment\\\", \\\"operation\\\": \\\"delete\\\", \\\"query\\\": \\\"DELETE FROM deployment WHERE id=id\\\", \\\"resultVar\\\": \\\"deploymentDeleteResult\\\" } }, { \\\"id\\\": \\\"logic_node_1739601748474_2\\\", \\\"type\\\": \\\"logic\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 400 }, \\\"data\\\": { \\\"label\\\": \\\"Logic\\\", \\\"fields\\\": [], \\\"queryFields\\\": [], \\\"code\\\": \\\"//commented logic\\\" } }, { \\\"id\\\": \\\"output_node_1739601748474_2\\\", \\\"type\\\": \\\"outputs\\\", \\\"position\\\": { \\\"x\\\": 100, \\\"y\\\": 500 }, \\\"data\\\": { \\\"label\\\": \\\"Response\\\", \\\"outputType\\\": \\\"json\\\", \\\"fields\\\": [ { \\\"name\\\": \\\"error\\\", \\\"type\\\": \\\"boolean\\\" }, { \\\"name\\\": \\\"id\\\", \\\"type\\\": \\\"integer\\\" } ], \\\"statusCode\\\": 200, \\\"resultVar\\\": \\\"deploymentDeleteResult\\\" } } ], \\\"edges\\\": [ { \\\"id\\\": \\\"url-to-auth_1739601748474_2\\\", \\\"source\\\": \\\"url_node_1739601748474_2\\\", \\\"target\\\": \\\"auth_node_1739601748474_2\\\" }, { \\\"id\\\": \\\"auth-to-db_1739601748474_2\\\", \\\"source\\\": \\\"auth_node_1739601748474_2\\\", \\\"target\\\": \\\"db_delete_node_1739601748474_2\\\" }, { \\\"id\\\": \\\"db-to-logic_1739601748474_2\\\", \\\"source\\\": \\\"db_delete_node_1739601748474_2\\\", \\\"target\\\": \\\"logic_node_1739601748474_2\\\" }, { \\\"id\\\": \\\"logic-to-output_1739601748474_2\\\", \\\"source\\\": \\\"logic_node_1739601748474_2\\\", \\\"target\\\": \\\"output_node_1739601748474_2\\\" } ] } } ], \\\"roles\\\": [ { \\\"id\\\": \\\"role_admin_1739601142401\\\", \\\"name\\\": \\\"Super Admin\\\", \\\"slug\\\": \\\"super_admin\\\", \\\"permissions\\\": { \\\"routes\\\": [], \\\"canCreateUsers\\\": true, \\\"canEditUsers\\\": true, \\\"canDeleteUsers\\\": true, \\\"canManageRoles\\\": true, \\\"canLogin\\\": true, \\\"canRegister\\\": false, \\\"canForgot\\\": false, \\\"canReset\\\": false, \\\"canGoogleLogin\\\": false, \\\"canAppleLogin\\\": false, \\\"canMicrosoftLogin\\\": false, \\\"canMagicLinkLogin\\\": false, \\\"canTwitterLogin\\\": false, \\\"needs2FA\\\": false, \\\"canSetPermissions\\\": true, \\\"canPreference\\\": true, \\\"canVerifyEmail\\\": true, \\\"canUpload\\\": false, \\\"canStripe\\\": false, \\\"canStripeWebhook\\\": false, \\\"canRealTime\\\": false, \\\"canAI\\\": true, \\\"canUpdateEmail\\\": true, \\\"canUpdatePassword\\\": true, \\\"canUpdateOtherUsers\\\": true, \\\"treeql\\\": { \\\"enabled\\\": true, \\\"models\\\": { \\\"user\\\": { \\\"allowed\\\": true, \\\"blacklistedFields\\\": [ \\\"password\\\" ], \\\"operations\\\": { \\\"get\\\": true, \\\"getOne\\\": true, \\\"getAll\\\": true, \\\"post\\\": true, \\\"put\\\": true, \\\"delete\\\": true, \\\"paginate\\\": true, \\\"join\\\": true } }, \\\"preference\\\": { \\\"allowed\\\": true, \\\"blacklistedFields\\\": [], \\\"operations\\\": { \\\"get\\\": true, \\\"getOne\\\": true, \\\"getAll\\\": true, \\\"post\\\": true, \\\"put\\\": true, \\\"delete\\\": true, \\\"paginate\\\": true, \\\"join\\\": true } }, \\\"tokens\\\": { \\\"allowed\\\": true, \\\"blacklistedFields\\\": [ \\\"token\\\" ], \\\"operations\\\": { \\\"get\\\": true, \\\"getOne\\\": true, \\\"getAll\\\": true, \\\"post\\\": true, \\\"put\\\": true, \\\"delete\\\": true, \\\"paginate\\\": true, \\\"join\\\": true } }, \\\"job\\\": { \\\"allowed\\\": true, \\\"blacklistedFields\\\": [], \\\"operations\\\": { \\\"get\\\": true, \\\"getOne\\\": true, \\\"getAll\\\": true, \\\"post\\\": true, \\\"put\\\": true, \\\"delete\\\": true, \\\"paginate\\\": true, \\\"join\\\": true } } } } } } ]}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/build/backend", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "build", + "backend" + ] + } + }, + "response": [ + { + "name": "Create Repo", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"coretest_frontend\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/core/custom/repository", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "core", + "custom", + "repository" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "2239" + }, + { + "key": "ETag", + "value": "W/\"8bf-yf+jq76zrz3MmxWFcCNyY4c0n1o\"" + }, + { + "key": "Date", + "value": "Wed, 19 Feb 2025 22:21:41 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"error\": false,\n \"model\": {\n \"id\": 771,\n \"owner\": {\n \"id\": 2,\n \"login\": \"mkdlabs\",\n \"login_name\": \"\",\n \"source_id\": 0,\n \"full_name\": \"\",\n \"email\": \"\",\n \"avatar_url\": \"http://23.29.118.76:3000/avatars/5bd6a72c7040f4781b0f4f63548ce6b3\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs\",\n \"language\": \"\",\n \"is_admin\": false,\n \"last_login\": \"0001-01-01T00:00:00Z\",\n \"created\": \"2022-11-22T17:30:12Z\",\n \"restricted\": false,\n \"active\": false,\n \"prohibit_login\": false,\n \"location\": \"\",\n \"website\": \"\",\n \"description\": \"\",\n \"visibility\": \"private\",\n \"followers_count\": 1,\n \"following_count\": 0,\n \"starred_repos_count\": 0,\n \"username\": \"mkdlabs\"\n },\n \"name\": \"coretest_frontend\",\n \"full_name\": \"mkdlabs/coretest_frontend\",\n \"description\": \"\",\n \"empty\": false,\n \"private\": false,\n \"fork\": false,\n \"template\": false,\n \"parent\": null,\n \"mirror\": false,\n \"size\": 25,\n \"language\": \"\",\n \"languages_url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend/languages\",\n \"html_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend\",\n \"url\": \"http://23.29.118.76:3000/api/v1/repos/mkdlabs/coretest_frontend\",\n \"link\": \"\",\n \"ssh_url\": \"root@localhost:mkdlabs/coretest_frontend.git\",\n \"clone_url\": \"http://23.29.118.76:3000/mkdlabs/coretest_frontend.git\",\n \"original_url\": \"\",\n \"website\": \"\",\n \"stars_count\": 0,\n \"forks_count\": 0,\n \"watchers_count\": 1,\n \"open_issues_count\": 0,\n \"open_pr_counter\": 0,\n \"release_counter\": 0,\n \"default_branch\": \"master\",\n \"archived\": false,\n \"created_at\": \"2025-02-19T22:20:33Z\",\n \"updated_at\": \"2025-02-19T22:20:48Z\",\n \"archived_at\": \"1970-01-01T00:00:00Z\",\n \"permissions\": {\n \"admin\": true,\n \"push\": true,\n \"pull\": true\n },\n \"has_issues\": true,\n \"internal_tracker\": {\n \"enable_time_tracker\": true,\n \"allow_only_contributors_to_track_time\": true,\n \"enable_issue_dependencies\": true\n },\n \"has_wiki\": true,\n \"has_pull_requests\": true,\n \"has_projects\": true,\n \"projects_mode\": \"all\",\n \"has_releases\": true,\n \"has_packages\": true,\n \"has_actions\": true,\n \"ignore_whitespace_conflicts\": false,\n \"allow_merge_commits\": true,\n \"allow_rebase\": true,\n \"allow_rebase_explicit\": true,\n \"allow_squash_merge\": true,\n \"allow_fast_forward_only_merge\": true,\n \"allow_rebase_update\": true,\n \"default_delete_branch_after_merge\": false,\n \"default_merge_style\": \"merge\",\n \"default_allow_maintainer_edit\": false,\n \"avatar_url\": \"\",\n \"internal\": true,\n \"mirror_interval\": \"\",\n \"object_format_name\": \"sha1\",\n \"mirror_updated\": \"0001-01-01T00:00:00Z\",\n \"repo_transfer\": null,\n \"topics\": [],\n \"licenses\": null\n }\n}" + } + ] + } + ] + }, + { + "name": "Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"adminsuper@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/login", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "login" + ], + "variable": [ + { + "key": "project", + "value": "core" + }, + { + "key": "role", + "value": "super_admin" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoic3VwZXJfYWRtaW4iLCJpYXQiOjE3Mzk2MDQ1NDcsImV4cCI6MTc0MDIwOTM0N30.9mELd9NnKoU1ycsEo5vE8w0Zh5nlkwzQWSOBSdomVbg", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Register", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp43@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"first_name\": \"Member\",\r\n \"last_name\": \"User\",\r\n \"phone\": \"\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/register", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "register" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"adminsuper@manaknight.com\",\r\n \"password\": \"a123456\",\r\n \"role\": \"super_admin\",\r\n \"is_refresh\": \"true\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/login", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "login" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + } + ] + } + }, + "response": [] + }, + { + "name": "Refresh Token", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/refresh_token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "refresh_token" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Reset", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"code\": \"37078626\",\r\n \"password\": \"a123456\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/reset", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "reset" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Email", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Password", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Verify account", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ5OTQ0NywiZXhwIjoxNzM3NTAzMDQ3fQ.X6ne_jJ--WpFpo6cQKx87ClpxUoge-dXlnKg1DMQOvI", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"mytestapp2334@manaknight.com\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/update/email", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "update", + "email" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Forgot", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/:project/:role/lambda/refresh_token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + ":project", + ":role", + "lambda", + "refresh_token" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "member" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get One", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=tokens&exclude=tokens.token", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "tokens" + }, + { + "key": "join", + "value": "author", + "disabled": true + }, + { + "key": "exclude", + "value": "tokens.token" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "user" + }, + { + "key": "id", + "value": "6" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Many", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id?join=user&include=user_id,type,user.status,user.email,user.id&exclude=token,user.password", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "query": [ + { + "key": "join", + "value": "user" + }, + { + "key": "include", + "value": "user_id,type,user.status,user.email,user.id" + }, + { + "key": "exclude", + "value": "token,user.password" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "tokens" + }, + { + "key": "id", + "value": "6,18" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Get Paginate", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywicm9sZSI6Im1lbWJlciIsImlhdCI6MTczNzQ2MjgwMiwiZXhwIjoxNzM4MDY3NjAyfQ.L4qEzPD2zbtpO7yzgzGRazrSTnIytIF24nhUt-_RsZU\",\r\n \"user_id\": \"13\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table?join=tokens&page=1,5&exclude=password,tokens.token&filter=id,gt,16", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "query": [ + { + "key": "join", + "value": "tokens" + }, + { + "key": "page", + "value": "1,5" + }, + { + "key": "exclude", + "value": "password,tokens.token" + }, + { + "key": "include", + "value": "id,email,tokens.id", + "disabled": true + }, + { + "key": "filter", + "value": "id,gt,16" + } + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "user" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Create", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Emmy\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Update", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + }, + { + "name": "Treeql Delete", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNiwicm9sZSI6InN1cGVyX2FkbWluIiwiaWF0IjoxNzM4ODczOTEyLCJleHAiOjE3Mzk0Nzg3MTJ9.p_766EEpnwVoomo3VUqHJX1V7YwHPXkHXCt1v2tcOSA", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"Joe Update\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{baseUrl}}/v1/api/records/:project/:role/:table/:id", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "v1", + "api", + "records", + ":project", + ":role", + ":table", + ":id" + ], + "variable": [ + { + "key": "project", + "value": "mytestapp" + }, + { + "key": "role", + "value": "super_admin" + }, + { + "key": "table", + "value": "author" + }, + { + "key": "id", + "value": "2" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:5172", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/src/assets/fonts/Inter-Black.otf b/src/assets/fonts/Inter-Black.otf new file mode 100644 index 0000000..44d1779 Binary files /dev/null and b/src/assets/fonts/Inter-Black.otf differ diff --git a/src/assets/fonts/Inter-Bold.otf b/src/assets/fonts/Inter-Bold.otf new file mode 100644 index 0000000..58a3807 Binary files /dev/null and b/src/assets/fonts/Inter-Bold.otf differ diff --git a/src/assets/fonts/Inter-ExtraBold.otf b/src/assets/fonts/Inter-ExtraBold.otf new file mode 100644 index 0000000..66cd952 Binary files /dev/null and b/src/assets/fonts/Inter-ExtraBold.otf differ diff --git a/src/assets/fonts/Inter-ExtraLight.otf b/src/assets/fonts/Inter-ExtraLight.otf new file mode 100644 index 0000000..b603db3 Binary files /dev/null and b/src/assets/fonts/Inter-ExtraLight.otf differ diff --git a/src/assets/fonts/Inter-Light.otf b/src/assets/fonts/Inter-Light.otf new file mode 100644 index 0000000..7da794b Binary files /dev/null and b/src/assets/fonts/Inter-Light.otf differ diff --git a/src/assets/fonts/Inter-Medium.otf b/src/assets/fonts/Inter-Medium.otf new file mode 100644 index 0000000..f44f89a Binary files /dev/null and b/src/assets/fonts/Inter-Medium.otf differ diff --git a/src/assets/fonts/Inter-Regular.otf b/src/assets/fonts/Inter-Regular.otf new file mode 100644 index 0000000..2d0bd1d Binary files /dev/null and b/src/assets/fonts/Inter-Regular.otf differ diff --git a/src/assets/fonts/Inter-SemiBold.otf b/src/assets/fonts/Inter-SemiBold.otf new file mode 100644 index 0000000..52c8455 Binary files /dev/null and b/src/assets/fonts/Inter-SemiBold.otf differ diff --git a/src/assets/fonts/Inter-Thin.otf b/src/assets/fonts/Inter-Thin.otf new file mode 100644 index 0000000..568a185 Binary files /dev/null and b/src/assets/fonts/Inter-Thin.otf differ diff --git a/src/assets/fonts/InterDisplay-Black.otf b/src/assets/fonts/InterDisplay-Black.otf new file mode 100644 index 0000000..d698536 Binary files /dev/null and b/src/assets/fonts/InterDisplay-Black.otf differ diff --git a/src/assets/images/db-synced.gif b/src/assets/images/db-synced.gif new file mode 100644 index 0000000..189903f Binary files /dev/null and b/src/assets/images/db-synced.gif differ diff --git a/src/assets/images/empty-page.png b/src/assets/images/empty-page.png new file mode 100644 index 0000000..78c34f9 Binary files /dev/null and b/src/assets/images/empty-page.png differ diff --git a/src/assets/images/index.ts b/src/assets/images/index.ts new file mode 100644 index 0000000..25d588b --- /dev/null +++ b/src/assets/images/index.ts @@ -0,0 +1,8 @@ +export { default as LoginBg } from "./login-bg.jpg"; +export { default as LoginBgNew } from "./login-new-bg.png"; +export { default as EmptyPageImg } from "./empty-page.png"; +export { default as MapView } from "./mapview.png"; +export { default as ScannerCode } from "./scannercode.png"; +export { default as NoDbConfigIllustration } from "./no-db-config.png"; +export { default as DbSyncedGif } from "./db-synced.gif"; +export { default as MKDLOGO } from "./mkd_logo.png"; diff --git a/src/assets/images/login-bg.jpg b/src/assets/images/login-bg.jpg new file mode 100644 index 0000000..0339ddf Binary files /dev/null and b/src/assets/images/login-bg.jpg differ diff --git a/src/assets/images/login-new-bg.png b/src/assets/images/login-new-bg.png new file mode 100644 index 0000000..5c7cf5b Binary files /dev/null and b/src/assets/images/login-new-bg.png differ diff --git a/src/assets/images/mapview.png b/src/assets/images/mapview.png new file mode 100644 index 0000000..1fb11f7 Binary files /dev/null and b/src/assets/images/mapview.png differ diff --git a/src/assets/images/mkd_logo.png b/src/assets/images/mkd_logo.png new file mode 100644 index 0000000..83b2786 Binary files /dev/null and b/src/assets/images/mkd_logo.png differ diff --git a/src/assets/images/no-db-config.png b/src/assets/images/no-db-config.png new file mode 100644 index 0000000..c7e8ad9 Binary files /dev/null and b/src/assets/images/no-db-config.png differ diff --git a/src/assets/images/scannercode.png b/src/assets/images/scannercode.png new file mode 100644 index 0000000..c27baa2 Binary files /dev/null and b/src/assets/images/scannercode.png differ diff --git a/src/assets/svgs/AlertCircle.tsx b/src/assets/svgs/AlertCircle.tsx new file mode 100644 index 0000000..86c1362 --- /dev/null +++ b/src/assets/svgs/AlertCircle.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +const AlertCircle = ({ className = "", stroke = "#334564" }) => { + return ( + + + + + + ); +}; + +export default AlertCircle; diff --git a/src/assets/svgs/AudioFileIcon.tsx b/src/assets/svgs/AudioFileIcon.tsx new file mode 100644 index 0000000..588aec5 --- /dev/null +++ b/src/assets/svgs/AudioFileIcon.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const AudioFileIcon = ({ className = "", fill = "#4f46e5", onClick = () => { } }) => { + return ( + + ); +}; + +export default AudioFileIcon; diff --git a/src/assets/svgs/CalendarIcon.tsx b/src/assets/svgs/CalendarIcon.tsx new file mode 100644 index 0000000..43c9858 --- /dev/null +++ b/src/assets/svgs/CalendarIcon.tsx @@ -0,0 +1,102 @@ +interface CalendarIconProps { + onClick?: () => void; + className?: string; + fill?: string; + stroke?: string; + pathFill?: string; +} + +const CalendarIcon = ({ + onClick, + className, + fill = "none", + stroke = "#1F1D1A", + pathFill = "none", +}: CalendarIconProps) => ( + + + + + + + + + + + + +); + +export default CalendarIcon; diff --git a/src/assets/svgs/CaptureSpatialIcon.tsx b/src/assets/svgs/CaptureSpatialIcon.tsx new file mode 100644 index 0000000..728c4e9 --- /dev/null +++ b/src/assets/svgs/CaptureSpatialIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const CaptureSpatialIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + + + + + + ); +}; + +export default CaptureSpatialIcon; \ No newline at end of file diff --git a/src/assets/svgs/CaretLeft.tsx b/src/assets/svgs/CaretLeft.tsx new file mode 100644 index 0000000..04cab45 --- /dev/null +++ b/src/assets/svgs/CaretLeft.tsx @@ -0,0 +1,22 @@ +import React from "react"; + +export const CaretLeft = ({ className = "" }) => { + return ( + + + + ); +}; diff --git a/src/assets/svgs/CheckIcon.tsx b/src/assets/svgs/CheckIcon.tsx new file mode 100644 index 0000000..b32e594 --- /dev/null +++ b/src/assets/svgs/CheckIcon.tsx @@ -0,0 +1,18 @@ +export const CheckIcon = () => ( + <> + + + + +); diff --git a/src/assets/svgs/Chevron.svg b/src/assets/svgs/Chevron.svg new file mode 100644 index 0000000..1cb23be --- /dev/null +++ b/src/assets/svgs/Chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/ChevronUpIcon.tsx b/src/assets/svgs/ChevronUpIcon.tsx new file mode 100644 index 0000000..5cd06d6 --- /dev/null +++ b/src/assets/svgs/ChevronUpIcon.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +const ChevronUpIcon = ({ className = "", stroke = "black", onClick = () => { } }) => { + return ( + + + + + + ); +}; + +export default ChevronUpIcon; diff --git a/src/assets/svgs/CloseIcon.tsx b/src/assets/svgs/CloseIcon.tsx new file mode 100644 index 0000000..74bd279 --- /dev/null +++ b/src/assets/svgs/CloseIcon.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +export const CloseIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; diff --git a/src/assets/svgs/ControlIcon.tsx b/src/assets/svgs/ControlIcon.tsx new file mode 100644 index 0000000..192fefa --- /dev/null +++ b/src/assets/svgs/ControlIcon.tsx @@ -0,0 +1,34 @@ +import React from "react"; + +const ControlIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + + + ); +}; + +export default ControlIcon; diff --git a/src/assets/svgs/CopyIcon.tsx b/src/assets/svgs/CopyIcon.tsx new file mode 100644 index 0000000..027b1d3 --- /dev/null +++ b/src/assets/svgs/CopyIcon.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +export const CopyIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + + + + + + + ); +}; diff --git a/src/assets/svgs/DangerIcon.tsx b/src/assets/svgs/DangerIcon.tsx new file mode 100644 index 0000000..0a0d84c --- /dev/null +++ b/src/assets/svgs/DangerIcon.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +export const DangerIcon = ( { className } ) => { + return ( + + + + + ) +} diff --git a/src/assets/svgs/DatabaseIcon.tsx b/src/assets/svgs/DatabaseIcon.tsx new file mode 100644 index 0000000..18a53d0 --- /dev/null +++ b/src/assets/svgs/DatabaseIcon.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const DatabaseIcon = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + + ) +}; + +export default DatabaseIcon; diff --git a/src/assets/svgs/DownloadIcon.tsx b/src/assets/svgs/DownloadIcon.tsx new file mode 100644 index 0000000..dbc77ae --- /dev/null +++ b/src/assets/svgs/DownloadIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const DownloadIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default DownloadIcon; \ No newline at end of file diff --git a/src/assets/svgs/EditIcon.tsx b/src/assets/svgs/EditIcon.tsx new file mode 100644 index 0000000..b469a80 --- /dev/null +++ b/src/assets/svgs/EditIcon.tsx @@ -0,0 +1,26 @@ +import React from "react"; + +const EditIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + ); +}; + +export default EditIcon; diff --git a/src/assets/svgs/FileAudioIcon.tsx b/src/assets/svgs/FileAudioIcon.tsx new file mode 100644 index 0000000..c996a0a --- /dev/null +++ b/src/assets/svgs/FileAudioIcon.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const FileAudioIcon = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + + ) +}; + +export default FileAudioIcon; diff --git a/src/assets/svgs/FileLineIcon.tsx b/src/assets/svgs/FileLineIcon.tsx new file mode 100644 index 0000000..3585c6f --- /dev/null +++ b/src/assets/svgs/FileLineIcon.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const FileLineIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + ); +}; + +export default FileLineIcon; \ No newline at end of file diff --git a/src/assets/svgs/FileMemoIcon.tsx b/src/assets/svgs/FileMemoIcon.tsx new file mode 100644 index 0000000..1d87a67 --- /dev/null +++ b/src/assets/svgs/FileMemoIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const FileMemoIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default FileMemoIcon; \ No newline at end of file diff --git a/src/assets/svgs/FileVerticalLineIcon.tsx b/src/assets/svgs/FileVerticalLineIcon.tsx new file mode 100644 index 0000000..8a9b4fe --- /dev/null +++ b/src/assets/svgs/FileVerticalLineIcon.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const FileVerticalLineIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + ); +}; + +export default FileVerticalLineIcon; \ No newline at end of file diff --git a/src/assets/svgs/FolderIcon.tsx b/src/assets/svgs/FolderIcon.tsx new file mode 100644 index 0000000..33ebf0e --- /dev/null +++ b/src/assets/svgs/FolderIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const FolderIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default FolderIcon; \ No newline at end of file diff --git a/src/assets/svgs/GitIcon.tsx b/src/assets/svgs/GitIcon.tsx new file mode 100644 index 0000000..9405dfe --- /dev/null +++ b/src/assets/svgs/GitIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const GitIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default GitIcon; \ No newline at end of file diff --git a/src/assets/svgs/HamburgerMenuIcon.tsx b/src/assets/svgs/HamburgerMenuIcon.tsx new file mode 100644 index 0000000..360a0cd --- /dev/null +++ b/src/assets/svgs/HamburgerMenuIcon.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const HamburgerMenuIcon = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + + ); +}; + +export default HamburgerMenuIcon; diff --git a/src/assets/svgs/KebabIcon.tsx b/src/assets/svgs/KebabIcon.tsx new file mode 100644 index 0000000..2b4f43e --- /dev/null +++ b/src/assets/svgs/KebabIcon.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +const KebabIcon = ({ className = "", stroke = "#8D8D8D", onClick = () => { } }) => { + return ( + + + + + + ); +}; + +export default KebabIcon; diff --git a/src/assets/svgs/LeftBendArrow.tsx b/src/assets/svgs/LeftBendArrow.tsx new file mode 100644 index 0000000..0f6076a --- /dev/null +++ b/src/assets/svgs/LeftBendArrow.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const LeftBendArrow = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + + ) +} + +export default LeftBendArrow \ No newline at end of file diff --git a/src/assets/svgs/LoadCheckIcon.tsx b/src/assets/svgs/LoadCheckIcon.tsx new file mode 100644 index 0000000..64834fe --- /dev/null +++ b/src/assets/svgs/LoadCheckIcon.tsx @@ -0,0 +1,59 @@ +import React from "react"; + +const LoadCheckIcon = ({ + className = "", + stroke = "black", + onClick, + title, + icon = "check", +}) => { + const click = () => { + if (onClick) { + onClick(); + } + }; + return ( +
+ {icon === "loader" ? ( + + + + ) : null} + {icon === "check" ? ( + + + + ) : null} +
+ ); +}; + +export default LoadCheckIcon; diff --git a/src/assets/svgs/NarrowUpArrowIcon.tsx b/src/assets/svgs/NarrowUpArrowIcon.tsx new file mode 100644 index 0000000..ab776c8 --- /dev/null +++ b/src/assets/svgs/NarrowUpArrowIcon.tsx @@ -0,0 +1,29 @@ + +const NarrowUpArrowIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default NarrowUpArrowIcon; diff --git a/src/assets/svgs/PdfFileIcon.tsx b/src/assets/svgs/PdfFileIcon.tsx new file mode 100644 index 0000000..19479d0 --- /dev/null +++ b/src/assets/svgs/PdfFileIcon.tsx @@ -0,0 +1,8 @@ +import React from "react"; + +const PdfFileIcon = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + ); +}; + +export default PdfFileIcon; diff --git a/src/assets/svgs/PlusIcon.tsx b/src/assets/svgs/PlusIcon.tsx new file mode 100644 index 0000000..ac1c875 --- /dev/null +++ b/src/assets/svgs/PlusIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const PlusIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default PlusIcon; \ No newline at end of file diff --git a/src/assets/svgs/PostmanIcon.tsx b/src/assets/svgs/PostmanIcon.tsx new file mode 100644 index 0000000..fd4510b --- /dev/null +++ b/src/assets/svgs/PostmanIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +const PostmanIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + ); +}; + +export default PostmanIcon; \ No newline at end of file diff --git a/src/assets/svgs/ReactIcon.tsx b/src/assets/svgs/ReactIcon.tsx new file mode 100644 index 0000000..789cb70 --- /dev/null +++ b/src/assets/svgs/ReactIcon.tsx @@ -0,0 +1,8 @@ +import React from "react"; + +const ReactIcon = ({ className = "", fill = "#6f6f6f", stroke = "#6f6f6f", onClick = () => { } }) => { + return ( + react ) +}; + +export default ReactIcon; diff --git a/src/assets/svgs/RightBendArrow.tsx b/src/assets/svgs/RightBendArrow.tsx new file mode 100644 index 0000000..46c651a --- /dev/null +++ b/src/assets/svgs/RightBendArrow.tsx @@ -0,0 +1,8 @@ +import React from 'react' + +const RightBendArrow = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + ) +} + +export default RightBendArrow \ No newline at end of file diff --git a/src/assets/svgs/RobotIcon.tsx b/src/assets/svgs/RobotIcon.tsx new file mode 100644 index 0000000..e71d0fb --- /dev/null +++ b/src/assets/svgs/RobotIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const RobotIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default RobotIcon; \ No newline at end of file diff --git a/src/assets/svgs/SettingIcon.tsx b/src/assets/svgs/SettingIcon.tsx new file mode 100644 index 0000000..26a2ac7 --- /dev/null +++ b/src/assets/svgs/SettingIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const SettingIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default SettingIcon; \ No newline at end of file diff --git a/src/assets/svgs/Spinner.tsx b/src/assets/svgs/Spinner.tsx new file mode 100644 index 0000000..3fe3a09 --- /dev/null +++ b/src/assets/svgs/Spinner.tsx @@ -0,0 +1,20 @@ +import React, { useId } from "react"; +import MoonLoader from "react-spinners/MoonLoader"; +const override = { + // display: "block", + // margin: "0 auto", + borderColor: "red", +}; +export const Spinner = ({ className = "", size = 20, color = "#ffffff" }) => { + const id = useId(); + return ( + + ); +}; diff --git a/src/assets/svgs/SpiralArrow.tsx b/src/assets/svgs/SpiralArrow.tsx new file mode 100644 index 0000000..3c9a269 --- /dev/null +++ b/src/assets/svgs/SpiralArrow.tsx @@ -0,0 +1,24 @@ +export default function SpiralArrow() { + return ( + + + + + ); +} diff --git a/src/assets/svgs/SyncIcon.tsx b/src/assets/svgs/SyncIcon.tsx new file mode 100644 index 0000000..7ad7208 --- /dev/null +++ b/src/assets/svgs/SyncIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const SyncIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default SyncIcon; \ No newline at end of file diff --git a/src/assets/svgs/ThreeDotsHorizontal.tsx b/src/assets/svgs/ThreeDotsHorizontal.tsx new file mode 100644 index 0000000..832a9ae --- /dev/null +++ b/src/assets/svgs/ThreeDotsHorizontal.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +const ThreeDotsHorizontal = ({ className = "", fill = "#8D8D8D", onClick = () => { } }) => { + return ( + + + + + + ); +}; + +export default ThreeDotsHorizontal; \ No newline at end of file diff --git a/src/assets/svgs/TrashIcon.tsx b/src/assets/svgs/TrashIcon.tsx new file mode 100644 index 0000000..df7c2b7 --- /dev/null +++ b/src/assets/svgs/TrashIcon.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +const TrashIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default TrashIcon; diff --git a/src/assets/svgs/TreeStructureIcon.tsx b/src/assets/svgs/TreeStructureIcon.tsx new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/src/assets/svgs/TreeStructureIcon.tsx @@ -0,0 +1,8 @@ +import React from "react"; + +const TreeStructureIcon = ({ className = "", fill = "#6f6f6f", onClick = () => { } }) => { + return ( + ) +}; + +export default TreeStructureIcon; diff --git a/src/assets/svgs/XIcon.tsx b/src/assets/svgs/XIcon.tsx new file mode 100644 index 0000000..3b75285 --- /dev/null +++ b/src/assets/svgs/XIcon.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const XIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + ); +}; + +export default XIcon; diff --git a/src/assets/svgs/adminHeader/DashboardIcon.tsx b/src/assets/svgs/adminHeader/DashboardIcon.tsx new file mode 100644 index 0000000..15a02a1 --- /dev/null +++ b/src/assets/svgs/adminHeader/DashboardIcon.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const DashboardIcon = () => { + return ( + + + + + ) +} + +export default DashboardIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/DeploymentIcon.tsx b/src/assets/svgs/adminHeader/DeploymentIcon.tsx new file mode 100644 index 0000000..b859ab3 --- /dev/null +++ b/src/assets/svgs/adminHeader/DeploymentIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const DeploymentIcon = () => { + return ( + + + + ) +} + +export default DeploymentIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/PaymentIcon.tsx b/src/assets/svgs/adminHeader/PaymentIcon.tsx new file mode 100644 index 0000000..2d72174 --- /dev/null +++ b/src/assets/svgs/adminHeader/PaymentIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const PaymentIcon = () => { + return ( + + + + ) +} + +export default PaymentIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/ProductIcon.tsx b/src/assets/svgs/adminHeader/ProductIcon.tsx new file mode 100644 index 0000000..4929517 --- /dev/null +++ b/src/assets/svgs/adminHeader/ProductIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react' + +const ProductIcon = () => { + return ( + + + + + + ) +} + +export default ProductIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/ProjectIcon.tsx b/src/assets/svgs/adminHeader/ProjectIcon.tsx new file mode 100644 index 0000000..4c01b62 --- /dev/null +++ b/src/assets/svgs/adminHeader/ProjectIcon.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const ProjectIcon = () => { + return ( + + + + + ) +} + +export default ProjectIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/SowIcon.tsx b/src/assets/svgs/adminHeader/SowIcon.tsx new file mode 100644 index 0000000..bc9fa95 --- /dev/null +++ b/src/assets/svgs/adminHeader/SowIcon.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const SowIcon = () => { + return ( + + + + + ) +} + +export default SowIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/WireframeIcon.tsx b/src/assets/svgs/adminHeader/WireframeIcon.tsx new file mode 100644 index 0000000..fb54167 --- /dev/null +++ b/src/assets/svgs/adminHeader/WireframeIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react' + +const WireframeIcon = () => { + return ( + + + + + + + + + + ) +} + +export default WireframeIcon \ No newline at end of file diff --git a/src/assets/svgs/adminHeader/index.js b/src/assets/svgs/adminHeader/index.js new file mode 100644 index 0000000..af3e00f --- /dev/null +++ b/src/assets/svgs/adminHeader/index.js @@ -0,0 +1,7 @@ +export { default as DashboardIcon } from "./DashboardIcon"; +export { default as PaymentIcon } from "./PaymentIcon"; +export { default as ProductIcon } from "./ProductIcon"; +export { default as SowIcon } from "./SowIcon"; +export { default as WireframeIcon } from "./WireframeIcon"; +export { default as ProjectIcon } from "./ProjectIcon"; +export { default as DeploymentIcon } from "./DeploymentIcon"; diff --git a/src/assets/svgs/index.ts b/src/assets/svgs/index.ts new file mode 100644 index 0000000..9f27e70 --- /dev/null +++ b/src/assets/svgs/index.ts @@ -0,0 +1,41 @@ +import { lazy } from "react"; + +export { default as ChevronDown } from "./Chevron.svg"; +export { Spinner } from "./Spinner"; +export { DangerIcon } from "./DangerIcon"; +export { CloseIcon } from "./CloseIcon"; +export { CaretLeft } from "./CaretLeft"; +export const ControlIcon = lazy(() => import("./ControlIcon")); +export const KebabIcon = lazy(() => import("./KebabIcon")); +export const TrashIcon = lazy(() => import("./TrashIcon")); +export const ChevronUpIcon = lazy(() => import("./ChevronUpIcon")); +export const LoadCheckIcon = lazy(() => import("./LoadCheckIcon")); +export const XIcon = lazy(() => import("./XIcon")); +export const EditIcon = lazy(() => import("./EditIcon")); +export const PlusIcon = lazy(() => import("./PlusIcon")); +export const ThreeDotsHorizontal = lazy(() => import("./ThreeDotsHorizontal")); +export const DownloadIcon = lazy(() => import("./DownloadIcon")); +export const GitIcon = lazy(() => import("./GitIcon")); +export const SettingIcon = lazy(() => import("./SettingIcon")); +export const SyncIcon = lazy(() => import("./SyncIcon")); +export const PostmanIcon = lazy(() => import("./PostmanIcon")); +export const CaptureSpatialIcon = lazy(() => import("./CaptureSpatialIcon")); +export const RobotIcon = lazy(() => import("./RobotIcon")); +export const FolderIcon = lazy(() => import("./FolderIcon")); +export const FileLineIcon = lazy(() => import("./FileLineIcon")); +export const FileVerticalLineIcon = lazy(() => + import("./FileVerticalLineIcon") +); +export const FileMemoIcon = lazy(() => import("./FileMemoIcon")); +export const HamburgerMenuIcon = lazy(() => import("./HamburgerMenuIcon")); +export const PdfFileIcon = lazy(() => import("./PdfFileIcon")); +export const FileAudioIcon = lazy(() => import("./FileAudioIcon")); +export const DatabaseIcon = lazy(() => import("./DatabaseIcon")); +export const TreeStructureIcon = lazy(() => import("./TreeStructureIcon")); +export const ReactIcon = lazy(() => import("./ReactIcon")); +export const AudioFileIcon = lazy(() => import("./AudioFileIcon")); +export const RightBendArrow = lazy(() => import("./RightBendArrow")); +export const LeftBendArrow = lazy(() => import("./LeftBendArrow")); +export const AlertCircle = lazy(() => import("./AlertCircle")); +export const NarrowUpArrowIcon = lazy(() => import("./NarrowUpArrowIcon")); +export const CalendarIcon = lazy(() => import("./CalendarIcon")); diff --git a/src/cn.js b/src/cn.js new file mode 100644 index 0000000..0b82cd0 --- /dev/null +++ b/src/cn.js @@ -0,0 +1,57 @@ +const fs = require('fs'); +const path = require('path'); + +function renameFiles(directory, fromExt, toExt) { + // Read the directory + fs.readdir(directory, { withFileTypes: true }, (err, files) => { + if (err) { + console.error('Error reading directory:', err); + return; + } + + files.forEach(file => { + const fullPath = path.join(directory, file.name); + + if (file.isDirectory()) { + // If it's a directory, recursively process it + renameFiles(fullPath, fromExt, toExt); + } else { + // Skip cn.js and .tsx files + if (file.name === 'cn.js' || path.extname(file.name) === '.tsx') { + return; + } + + // Check if file has the extension we want to change + if (path.extname(file.name) === fromExt) { + const newPath = path.join( + directory, + path.basename(file.name, fromExt) + toExt + ); + + // Rename the file + fs.rename(fullPath, newPath, err => { + if (err) { + console.error(`Error renaming ${file.name}:`, err); + } else { + console.log(`Renamed ${file.name} to ${path.basename(newPath)}`); + } + }); + } + } + }); + }); +} + +// Usage example: +// First argument is the directory to start from +// Second argument is the extension to change from (including the dot) +// Third argument is the extension to change to (including the dot) +const args = process.argv.slice(2); +if (args.length !== 3) { + console.log('Usage: node cn.js '); + console.log('Example: node cn.js . .js .ts'); + process.exit(1); +} + +const [directory, fromExt, toExt] = args; +renameFiles(path.resolve(directory), fromExt, toExt); \ No newline at end of file diff --git a/src/components/AATest/Entry/Entry.tsx b/src/components/AATest/Entry/Entry.tsx new file mode 100644 index 0000000..cfeeb75 --- /dev/null +++ b/src/components/AATest/Entry/Entry.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import List from "../List/List"; + +const Entry = () => { + return ; +}; + +export default Entry; diff --git a/src/components/AATest/InfiniteScrollTest/InfiniteScrollTest.tsx b/src/components/AATest/InfiniteScrollTest/InfiniteScrollTest.tsx new file mode 100644 index 0000000..e98c8f3 --- /dev/null +++ b/src/components/AATest/InfiniteScrollTest/InfiniteScrollTest.tsx @@ -0,0 +1,81 @@ +import React, { useCallback, useContext, useEffect, useState } from "react"; +import { MkdInfiniteScroll } from "@/components/MkdInfiniteScroll"; +import MkdSDK from "@/utils/MkdSDK"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; + +const InfiniteScrollTest = () => { + // NEXT Function example + const sdk = new MkdSDK(); + const { state, dispatch: authDispatch } = useContext(AuthContext); + const { state: globalState, dispatch: globalDispatch } = + useContext(GlobalContext); + + const [cursorPaginateData, setCursorPaginateData] = useState([]); + const [nextCursor, setNextCursor] = useState(0); + const [currentcursor, setCurrentCursor] = useState(0); + const [pageSize, setPageSize] = useState(10); + + const next = useCallback( + (initialized, cursor) => { + (async () => { + try { + sdk.setTable("user"); + const result = await sdk.callRestAPI( + { limit: pageSize, cursor: cursor }, + "CURSORPAGINATE" + ); + if (!result.error) { + if (!initialized) { + setCursorPaginateData(() => [...result?.list]); + } else { + setCursorPaginateData((prev) => [...prev, ...result?.list]); + } + setCurrentCursor(result?.cursor); + setNextCursor(result?.nextCursor); + } + } catch (error) { + // write your error logic here + const message = error?.response?.data?.message + ? error?.response?.data?.message + : error?.message; + showToast(globalDispatch, message, 4000, "error"); + tokenExpireError(authDispatch, message); + } + })(); + }, + [nextCursor, currentcursor, pageSize] + ); + + useEffect(() => { + next(); + }, []); + + // Example Usage + return ( + +
    + {cursorPaginateData.length + ? cursorPaginateData.map((data, index) => ( +
  • + {index + 1} {data?.last_name} {data?.first_name} +
  • + )) + : null} +
+
+ ); +}; + +export default InfiniteScrollTest; diff --git a/src/components/AATest/List/List.tsx b/src/components/AATest/List/List.tsx new file mode 100644 index 0000000..5eb1ced --- /dev/null +++ b/src/components/AATest/List/List.tsx @@ -0,0 +1,39 @@ +import React, { useEffect, useState } from "react"; + +const List = (props) => { + const [items, setItems] = useState([]); + const [selected, setSelected] = useState(""); + + useEffect(() => { + if (selected) { + const tempItems = items; + const position = tempItems.findIndex((item) => item === selected); + tempItems.splice(position, 1); + tempItems.unshift(selected); + + setItems(() => [...tempItems]); + } else { + setItems(() => [...props?.items]); + } + }, [selected]); + + return ( +
+
    + {items.length + ? items.map((item) => ( +
  • setSelected(item)} + key={item} + > + {item} +
  • + )) + : null} +
+
+ ); +}; + +export default List; diff --git a/src/components/AATest/index.ts b/src/components/AATest/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/components/AdminHeader/AdminHeader.tsx b/src/components/AdminHeader/AdminHeader.tsx new file mode 100644 index 0000000..8836f4a --- /dev/null +++ b/src/components/AdminHeader/AdminHeader.tsx @@ -0,0 +1,148 @@ +import { Link, NavLink } from "react-router-dom"; +import { PiUsersThreeFill } from "react-icons/pi"; +import { ProjectIcon, SowIcon, WireframeIcon } from "@/assets/svgs/adminHeader"; +import { RiAiGenerate } from "react-icons/ri"; +import { TbDatabaseEdit } from "react-icons/tb"; +import { useContexts } from "@/hooks/useContexts"; + +const NAV_ITEMS = [ + { + to: "/admin/requirements", + text: "Requirements", + icon: , + value: "sow", + }, + { + to: "/admin/build", + text: "Build", + icon: , + value: "wireframe", + }, + { + to: "/admin/baas", + text: ( + <> + Baas(deprecated) + + ), + icon: , + value: "baas", + }, + { + to: "/admin/generate-ui/button", + text: "Generate UI", + icon: , + value: "generate-ui", + }, + { + to: "/admin/generate-query/project_name", + text: "Generate Query", + icon: , + value: "generate-query", + }, + { + to: "/admin/users", + text: "Users", + icon: , + value: "users", + }, + // { + // to: "/admin/email", + // text: "Email", + // icon: , + // value: "email", + // }, +]; + +export const AdminHeader = () => { + const { + globalState: { isOpen, path }, + globalDispatch, + } = useContexts(); + + let toggleOpen = (open: boolean) => { + globalDispatch({ + type: "OPEN_SIDEBAR", + payload: { isOpen: open }, + }); + }; + + // sidebar-holder + return ( +
+
+
+ {isOpen && ( +
+ +

+ Baas Brand{" "} + (Admin) +

+ +
+ )} +
+ +
+
+
    + {NAV_ITEMS.map((item) => ( +
  • + +
    + {item.icon} + {isOpen && {item.text}} +
    +
    +
  • + ))} +
+
+
+
+
+ toggleOpen(!isOpen)}> + + + + +
+
+
+ ); +}; + +export default AdminHeader; diff --git a/src/components/AdminHeader/index.ts b/src/components/AdminHeader/index.ts new file mode 100644 index 0000000..3286fdc --- /dev/null +++ b/src/components/AdminHeader/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const AdminHeader = lazy(() => import("./AdminHeader")); + + \ No newline at end of file diff --git a/src/components/AdminWrapper/AdminWrapper.tsx b/src/components/AdminWrapper/AdminWrapper.tsx new file mode 100644 index 0000000..b3aaab8 --- /dev/null +++ b/src/components/AdminWrapper/AdminWrapper.tsx @@ -0,0 +1,49 @@ +import React, { Suspense, memo } from "react"; + +import { AdminHeader } from "@/components/AdminHeader"; +import { TopHeader } from "@/components/TopHeader"; +import { Spinner } from "@/assets/svgs"; +import { LazyLoad } from "@/components/LazyLoad"; + +const navigation = []; + +interface AdminWrapperProps { + children: React.ReactNode; +} + +const AdminWrapper = ({ children }: AdminWrapperProps) => { + return ( + +
+
+ +
+ + + +
+ } + > +
+ {children} +
+ +
+
+ +
+ ); +}; + +export default memo(AdminWrapper); diff --git a/src/components/AdminWrapper/index.ts b/src/components/AdminWrapper/index.ts new file mode 100644 index 0000000..2d3f509 --- /dev/null +++ b/src/components/AdminWrapper/index.ts @@ -0,0 +1 @@ +export { default as AdminWrapper } from "./AdminWrapper"; diff --git a/src/components/ApiBuilder/ApiBuilder.tsx b/src/components/ApiBuilder/ApiBuilder.tsx new file mode 100644 index 0000000..20afb0b --- /dev/null +++ b/src/components/ApiBuilder/ApiBuilder.tsx @@ -0,0 +1,454 @@ +import React, { useState, useEffect, useCallback } from "react"; +import LeftPanel from "./LeftPanel"; +import MiddlePanel from "./MiddlePanel"; +import RightPanel from "./RightPanel"; +import { generateUUID, slugify } from "../../utils/utils"; +import WireframeSDK from "../../utils/WireframeSDK"; +import BaasSDK from "../../utils/BaasSDK"; +import TreeSDK from "@/utils/TreeSDK"; +import Frame from "../../utils/templates/api/Frame"; +import lambdaAPIShell from "../../utils/templates/api/lambdaAPIShell"; +import { Endpoint } from "../../utils/types/ApiEndpoint"; +import { + makeBaasPostmanSchemaTemplate, + makePostmanCollection, +} from "../../utils/helpers/endpoints/makePostman"; +import { fetchApiTemplate } from "../../utils/templates/api/index"; +import { fetchLambdaEndpoint, lambdas } from "@/utils/templates/api/lambda"; +import { defaultEndpoints } from "@/utils/templates/api/default"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { buildTreeQLEndpoints } from "@/utils/templates/api/treeQL"; +import { GlobalContext, showToast } from "@/context/Global"; +import { tokenExpireError } from "@/context/Auth"; +import { GitIcon, PostmanIcon, ThreeDotsHorizontal } from "@/assets/svgs"; +import { DropdownOptions } from "@/components/DropdownOptions"; +import { DropdownOption } from "@/components/DropdownOptions/DropdownOption"; + +let bSdk = new BaasSDK(); + +const wSdk = new WireframeSDK(); + +function ApiBuilder({ wireframe, selectedRoute, handleEndpointSave, saveRef }) { + const { dispatch } = React.useContext(GlobalContext); + const [endpoints, setEndpoints] = useState([]); + const [project, setProject] = useState({}); + const [roles, setRoles] = useState([]); + const [selectedEndpointIndex, setSelectedEndpointIndex] = useState(null); + const [selectedField, setSelectedField] = useState(null); + const [isLoading, setIsLoading] = useState({ state: false, target: null }); + const [schema, setSchema] = useState([]); + + useEffect(() => { + (async function () { + let project = await getProject(); + await getRoles(); + let wire = await getWireframe(); + let schema = await getSchema(project); + + await setDefaultEndpoints(schema, JSON.parse(wire?.api_config)); + })(); + }, []); + + const setDefaultEndpoints = async (schema, currentEndpoints) => { + if (!Array.isArray(currentEndpoints)) { + currentEndpoints = []; + } + let treeQLEndpoints = buildTreeQLEndpoints(schema); + let filteredEndpoints = currentEndpoints + .filter((s) => s.type != "default") + .filter((s) => s.type != "treeql"); + const AllEndpoints = [ + ...filteredEndpoints, + ...defaultEndpoints, + ...treeQLEndpoints, + ]; + + setEndpoints(AllEndpoints); + await saveAPI(AllEndpoints); + }; + + const getWireframe = async () => { + try { + let res = await new TreeSDK().getOne("wireframe", wireframe?.id, { + join: "sow", + }); + return res.model; + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const getProject = async () => { + try { + bSdk.setTable("projects"); + const result = await bSdk.callRestAPI( + { id: Number(wireframe.project_id) }, + "GET" + ); + if (!result.error) { + setProject(result.model); + return result.model; + } + } catch (error) { + setIsLoading(false); + tokenExpireError(dispatch, error.message); + } + }; + + const getRoles = async () => { + try { + bSdk.setProjectId(project.slug); + bSdk.setSecret(project.secret); + bSdk.setTable("permission"); + const result = await bSdk.callRestAPI({}, "GETALL"); + if (!result.error) { + let projectRoles = result.list.map((role) => role.role); + setRoles(projectRoles); + } + } catch (error) { + setIsLoading({ state: false, target: null }); + tokenExpireError(dispatch, error.message); + } + }; + + const getSchema = async (project) => { + try { + bSdk.setProjectId(bSdk._baas_project_id); + bSdk.setSecret(bSdk._baas_secret); + const result = await bSdk.getSchemaTables(project.slug); + let schemaData = Object.entries(result); + schemaData = schemaData.map((model) => { + return { model: model[0], columns: model[1] }; + }); + if (!result.error) { + setSchema(schemaData); + return schemaData; + } + } catch (error) { + setIsLoading({ state: false, target: null }); + tokenExpireError( + dispatch, + error?.response?.data?.message + ? error?.response?.data?.message + : error?.message + ); + } + }; + + const onEndpointAdd = () => { + const newEndpoints = [...endpoints, Endpoint(generateUUID(), project.slug)]; + setEndpoints(newEndpoints); + setSelectedEndpointIndex(endpoints[endpoints.length - 1]?.id); + }; + + const onEndpointGroupAdd = (newEndpoints = []) => { + setEndpoints([...endpoints, ...newEndpoints]); + setSelectedEndpointIndex(endpoints[endpoints.length - 1]?.id); + }; + + const onEndpointDelete = (id) => { + setEndpoints(endpoints.filter((e) => e.id != id)); + setSelectedEndpointIndex(null); + }; + + const onEndpointSelect = (endpoint) => { + setSelectedEndpointIndex(endpoint.id); + setSelectedField(null); + }; + + const onEndpointUpdate = (field, value) => { + const newEndpoints = endpoints.map((endpoint) => { + if (endpoint.id == selectedEndpointIndex) { + endpoint[field] = value; + return endpoint; + } + return endpoint; + }); + + setEndpoints(newEndpoints); + }; + + const onSelectField = (field) => { + setSelectedField(field); + }; + + const saveAPI = async (endpoints) => { + // try { + // let result = await wSdk.saveApiConfig( + // wireframe.id, + // JSON.stringify(endpoints) + // ); + // if (result.error) throw new Error(result); + // showToast(dispatch, "Saved"); + // } catch (error) { + // alert("Something went wrong"); + // } + }; + + const handleSave = useCallback(() => { + // transform workflow to endpoint + // const tempWorkflows = workflows; + // const defaultConfig = tempWorkflows[0]; + const endpoint = { + ...selectedRoute, + }; + handleEndpointSave(endpoint); + }, [selectedRoute]); + + const handleCommitToRepo = async (e) => { + e.target.innerHTML = "Commiting"; + let commitContent = ""; + let files = []; + let customEndpoints = endpoints + .filter((e) => e.type != "default") + .filter((e) => e.type != "lambda"); + + lambdas.forEach((lambda) => { + let lambdaEndpoints = endpoints.filter((e) => e.group == lambda); + if (lambdaEndpoints.length == 0) return; + + let lambdaImports = fetchLambdaEndpoint(lambda)?.imports ?? ""; + let lambdaCommitContent = ``; + lambdaEndpoints.forEach((endpoint) => { + lambdaCommitContent += ` + + //Endpoint + /* + ${typeof endpoint.code !== "undefined" ? endpoint.code : ""} + */ + + `; + }); + + lambdaCommitContent = lambdaAPIShell(lambdaCommitContent, lambdaImports); + + files.push({ + path: `lambda/${lambda}.js`, + content: btoa(lambdaCommitContent), + }); + }); + + customEndpoints.forEach((endpoint) => { + commitContent += ` + //Description + /* + ${typeof endpoint.doc !== "undefined" ? endpoint.doc : ""} + */ + + //Endpoint + /* + ${typeof endpoint.code !== "undefined" ? endpoint.code : ""} + */ + `; + }); + commitContent = Frame( + commitContent, + makeBaasPostmanSchemaTemplate(customEndpoints) + ); + let postmanCollection = makePostmanCollection(customEndpoints, project); + + files.push({ + path: `${project.slug}PostmanCollection.json`, + content: btoa(postmanCollection), + }); + + files.push({ + path: `${project.slug}.js`, + content: btoa(commitContent), + }); + + files.push({ + path: "index.js", + content: btoa(fetchApiTemplate("index.js")), + }); + + files.push({ + path: "health.js", + content: btoa(fetchApiTemplate("health.js")), + }); + + customEndpoints.forEach((endpoint) => { + files.push({ + path: `test/${slugify(endpoint.name)}.test.js`, + content: btoa(endpoint.unit), + }); + }); + + const branch = prompt("Enter branch to commit"); + try { + let res = await wSdk.commitFilesToRepo( + project.slug, + `${project.slug}_backend`, + files, + true, + branch + ); + if (!res.error) { + showToast(dispatch, "Done"); + } + showToast(dispatch, "Commited to repo"); + } catch (error) { + showToast(dispatch, "Error Commiting to repo", "error"); + } + e.target.innerHTML = "Commit to repo"; + }; + + // TODO extract to a better location + const actions = [ + { + category: "db", + name: "Get Record by Field", + inputs: ["Return as", "Model", "Field", "Field Variable Name"], + async: true, + template: function (...args) { + return ` + sdk.setTable('${args[1]}') + const ${args[0]} = ${this.async && "await"} sdk.get({${args[2]} : ${ + args[3] + }}) + `; + }, + description: "This API returns a database record by field", + }, + { + category: "db", + name: "Delete Record", + inputs: ["model", "idVar"], + async: true, + template: function (...args) { + return ` + sdk.setTable('${args[1]}') + const ${args[0]} = ${this.async && "await"} sdk.delete({}, ${args[1]}) + `; + }, + description: "This API deletes a database record by id", + }, + ]; + + const threeDotsHorOptionsDropdown = [ + { + name: "Commit To Repo", + onClick: () => handleCommitToRepo(), + icon: , + }, + { + name: "Create Postman doc", + onClick: () => {}, + icon: , + }, + ]; + + return ( +
+
+
API
+
+
+ + {isLoading.state == true && isLoading.target == "save" ? ( + + + + ) : ( + + + + )} + + + + {isLoading.state == true && isLoading.target == "save" + ? "Saving" + : "Saved!"} + +
+ + {isLoading.state == true && isLoading.target == "save" + ? "Saving" + : "Save"} +   Changes + + } + iconWrapperClass="rounded-md border border-[#E0E0E0] p-2 hover:bg-[#F4F4F4] " + childrenWrapperClass="" + > + {threeDotsHorOptionsDropdown.map((item, index) => ( + + ))} + +
+
+
+ + e.id == selectedEndpointIndex)[0] + : null + } + onSelectField={onSelectField} + selectedField={selectedField} + /> + e.id == selectedEndpointIndex)[0] + : null + } + onFieldChange={(field, value) => onEndpointUpdate(field, value)} + actions={actions} + roles={roles} + /> +
+ +
+ ); +} + +export default ApiBuilder; diff --git a/src/components/ApiBuilder/EndpointLogic.tsx b/src/components/ApiBuilder/EndpointLogic.tsx new file mode 100644 index 0000000..38ee1e9 --- /dev/null +++ b/src/components/ApiBuilder/EndpointLogic.tsx @@ -0,0 +1,455 @@ +import React from "react"; +import WireframeSDK from "@/utils/WireframeSDK"; +import { formatCode } from "@/utils/utils"; +import "codemirror/lib/codemirror.css"; +import "codemirror/theme/material.css"; +import "codemirror/theme/base16-light.css"; +import "codemirror/mode/xml/xml"; +import "codemirror/mode/javascript/javascript"; +import "codemirror/mode/css/css"; +import "codemirror/addon/display/fullscreen.js"; +import "codemirror/addon/display/fullscreen.css"; +import { Controlled as ControlledEditor } from "react-codemirror2"; + +let wSDk = new WireframeSDK(); + +const EndPointLogic = ({ + selectedEndpoint, + selectedCategory, + setSelectedCategory, + selectedAction, + setSelectedAction, + handleActionInputChange, + handleActionInputSave, + actions, + fieldValue, + setFieldValue, + onFieldChange, + handleCodeEditorInputChange, +}) => { + React.useEffect(() => { + setCode(selectedEndpoint.code || ""); + setDoc(selectedEndpoint.doc || ""); + setUnitTest(selectedEndpoint.unit || ""); + }, []); + + const [activeTab, setActiveTab] = React.useState(1); + const [code, setCode] = React.useState(""); + const [doc, setDoc] = React.useState(""); + const [unitTest, setUnitTest] = React.useState(""); + + const getMiddlewareStack = (endpoint) => { + if (!endpoint.protected) { + return " middlewares "; + } + + if (endpoint.authorizedRoles?.length < 1) { + return "[ ...middlewares, TokenMiddleware()]"; + } + + return `[ ...middlewares, TokenMiddleware({ role: "${endpoint.authorizedRoles.join( + "|" + )}" }) ] `; + }; + const handleLogicChange = (value) => { + onFieldChange( + "code", + ` + ${getAPITopTemplate()} + ${value} + ${getAPIBottomTemplate()} + ` + ); + }; + + const getAPITopTemplate = () => { + return `app.${selectedEndpoint.method.toLowerCase()}('${ + selectedEndpoint.route + }', ${getMiddlewareStack(selectedEndpoint)} , async (req, res) => { + const sdk = req.sdk; + sdk.setProjectId(req.projectId) + try{ + `; + }; + + const getResponseTemplate = () => { + return Array.isArray(selectedEndpoint.response) + ? `{${selectedEndpoint.response.map( + (item) => `${item.key}: ${item.value}` + )} }` + : selectedEndpoint.response; + }; + const getAPIBottomTemplate = () => { + return ` + return res.status(200).json(${getResponseTemplate()}) + } catch (err) { + console.error(err); + res.status(403).json({ + error: true, + message: err.message + }); + } + }) + + `; + }; + + const onGPTRender = async (e) => { + let btnText = e.target.innerHTML; + e.target.innerHTML = "Processing..."; + try { + const prompt = `Given the code below fill in the logic provided in the comment and return complete route implementation. + + ${getAPITopTemplate()} + ${fieldValue} + ${getAPIBottomTemplate()} + `; + const result = await wSDk.askGptCustom(prompt); + + if (!result.error) { + setCode(result.message); + onFieldChange("code", result.message); + setActiveTab(2); + } + } catch (error) { + console.log("Error", error); + } + e.target.innerHTML = btnText; + }; + + const onGPTAddDoc = async (e) => { + let btnText = e.target.innerHTML; + e.target.innerHTML = "Processing..."; + try { + const prompt = `Given the code below provide the developer documentation. + + ${getAPITopTemplate()} + ${fieldValue} + ${getAPIBottomTemplate()} + `; + const result = await wSDk.askGptCustom(prompt.trim()); + + if (!result.error) { + setDoc(result.message); + onFieldChange("doc", result.message); + setActiveTab(3); + } + } catch (error) { + console.log("Error", error); + } + e.target.innerHTML = btnText; + }; + + const onGPTAddUnit = async (e) => { + try { + e.target.innerHTML = "Processing..."; + const prompt = `Given the nodejs express route below provide the jest unit test + + ${getAPITopTemplate()} + ${fieldValue} + ${getAPIBottomTemplate()} + `; + const result = await wSDk.askGptCustom(prompt.trim()); + + if (!result.error) { + setUnitTest(result.message); + onFieldChange("unit", result.message); + setActiveTab(4); + } + } catch (error) { + console.log("Error", error); + } + e.target.innerHTML = btnText; + }; + + const onAddValidation = () => { + const inputs = selectedEndpoint.inputs; + const body = inputs + .filter((i) => i.type === "body") + .filter((i) => i.rules != ""); + let bodyValidation = ``; + if (body?.length >= 1) { + bodyValidation = ` + let validation = await validateObject({ + ${body.map( + (input) => ` ${input.name}: '${input.rules}' + ` + )} + }, req.body,) + if (validation.error) return res.status(403).json(validation) + `; + } + const newCode = formatCode( + ` ${bodyValidation} \n ${selectedEndpoint.logic} ` + ); + onFieldChange("logic", newCode); + setFieldValue(newCode); + }; + + return ( +
+
+
setActiveTab(1)} + > + Code +
+
setActiveTab(2)} + > + Preview +
+
setActiveTab(3)} + > + Documentation +
+
setActiveTab(4)} + > + Unit Test +
+
+ + {/* CODE TAB */} + {activeTab == 1 && ( +
+

{getAPITopTemplate()}

+
+ { + handleLogicChange(value); + handleCodeEditorInputChange(value); + }} + value={`${fieldValue}`} + className="w-full" + options={{ + lineWrapping: true, + lint: true, + mode: "javascript", + lineNumbers: true, + styleActiveLine: true, + theme: "base16-light", + }} + /> +
+

{getAPIBottomTemplate()}

+
+ )} + {/* PREVIEW TAB */} + {activeTab == 2 && ( +
+ +
+ )} + {/* DOC TAB */} + {activeTab == 3 && ( +
+ +
+ )} + {/* UNIT TEST TAB */} + {activeTab == 4 && ( +
+ +
+ )} +
+ + + +
+ +
+
+

Actions

+
+ + +
+
+ +
+

+ {selectedCategory && selectedCategory} +

+ {selectedCategory && + actions + .filter((action) => action.category === selectedCategory) + .map((action, index) => ( + + ))} +
+
+
+

+ {selectedAction && selectedAction.name} +

+ {selectedAction && ( +
+

{selectedAction.description}

+ {selectedAction.inputs?.map((input, index) => ( +
+ + + handleActionInputChange(index, e.target.value) + } + className="mb-2 w-full rounded border border-gray-400 px-2 py-1" + /> +
+ ))} + +
+ )} +
+
+ ); +}; + +export default EndPointLogic; diff --git a/src/components/ApiBuilder/EndpointResponse.tsx b/src/components/ApiBuilder/EndpointResponse.tsx new file mode 100644 index 0000000..8f4af73 --- /dev/null +++ b/src/components/ApiBuilder/EndpointResponse.tsx @@ -0,0 +1,196 @@ +import { XIcon } from "@/assets/svgs"; +import React, { useState, useEffect } from "react"; +import { DataTypes } from "@/utils/options/DataTypes"; +import { getDefaultResponseValueByType } from "@/utils/options/DataTypes"; +import { generateUUID } from "@/utils/utils"; + +const EndpointResponse = ({ endpoint, onResponseChange }) => { + const [key, setKey] = useState(""); + const [parent, setParent] = useState(""); + const [valueType, setValueType] = useState(""); + const [error, setError] = useState(""); + const [generatedObject, setGeneratedObject] = useState([]); + + const getDefaultResponse = () => { + return [ + { + id: generateUUID(), + key: "error", + value: false, + valueType: "Boolean", + parent: null, + }, + { + id: generateUUID(), + key: "message", + value: "Operation successful", + valueType: "String", + parent: null, + }, + ]; + }; + const handleAddEntry = () => { + if (!key || !valueType) { + setError("Please fill in all fields."); + return; + } + const entry = { + id: generateUUID(), + key, + value: getDefaultResponseValueByType(valueType), + valueType, + parent, + }; + + setGeneratedObject((prevObject) => [...prevObject, entry]); + setKey(""); + setParent(""); + setValueType(""); + setError(""); + onResponseChange([...generatedObject, entry]); + }; + + const handleRemoveEntry = (id) => { + let updatedObject = []; + setGeneratedObject((prevObject) => { + updatedObject = prevObject.filter((obj) => obj.id != id); + return updatedObject; + }); + onResponseChange(updatedObject); + }; + + useEffect(() => { + setGeneratedObject( + typeof endpoint.response === "string" + ? getDefaultResponse() + : endpoint.response + ); + }, []); + + const renderResponse = (generatedObject, parent = "") => { + let items = generatedObject.filter((go) => go.parent == parent); + + let response = ( +
+ {items.map((obj, index) => ( +
+
+ {obj.valueType !== "Object" && obj.parent && ( + + + + + + )} +
+ + {obj.key} + {obj?.value && obj.valueType !== "Object" && `:${obj.value}`} + + ({obj.valueType}) +
+ + handleRemoveEntry(obj.id)} + className="cursor-pointer rounded-full p-1 hover:bg-[#e4e4e4]" + > + + +
+ +
+ {obj.valueType === "Object" + ? renderResponse(generatedObject, obj.id) + : null} +
+
+ ))} +
+ ); + + return response; + }; + + return ( +
+ setKey(e.target.value)} + placeholder="Key" + className="w-full rounded-md border border-[#C6C6C6] bg-white px-3 py-2 shadow-sm" + /> + + + + {error &&
{error}
} + +
+

Generated Object

+
{renderResponse(generatedObject)}
+
+
+ ); +}; + +export default EndpointResponse; diff --git a/src/components/ApiBuilder/LeftPanel.tsx b/src/components/ApiBuilder/LeftPanel.tsx new file mode 100644 index 0000000..52f84e3 --- /dev/null +++ b/src/components/ApiBuilder/LeftPanel.tsx @@ -0,0 +1,200 @@ +import React, { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { + CodeBracketIcon, +} from "@heroicons/react/20/solid"; +import { ModalPrompt } from "@/components/Modal"; +import { lambdas } from "@/utils/templates/api/lambda"; +import { fetchLambdaEndpoint } from "@/utils/templates/api/lambda"; +import { ModalSidebar } from "@/components/ModalSidebar"; +import { PlusIcon, TrashIcon } from "@/assets/svgs"; +import { DropdownOptions } from "@/components/DropdownOptions"; +import { DropdownOption } from "@/components/DropdownOptions/DropdownOption"; + +function LeftPanel({ + endpoints, + onEndpointAdd, + onEndpointGroupAdd, + onEndpointDelete, + onEndpointSelect, + selectedEndpointIndex, +}) { + const [showAddLambdaModal, setShowAddLambdaModal] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); + const [deleteID, setDeleteID] = useState(""); + + const handleAddLambda = (lambda) => { + const endpoints = fetchLambdaEndpoint(lambda)?.endpoints; + onEndpointGroupAdd([...endpoints]); + setShowAddLambdaModal(false); + } + + const openModal = (id) => { + setIsModalOpen(true); + setDeleteID(id); + }; + + const handleDelete = () => { + onEndpointDelete(deleteID); + setIsModalOpen(false); + }; + + const closeModal = () => { + setIsModalOpen(false); + }; + + const addPageDropdownOptions = [ + { + name: "Add Endpoint", + onClick: () => { onEndpointAdd() }, + icon: + }, + { + name: "Add Lambda", + onClick: () => { setShowAddLambdaModal(true) }, + icon: + } + ]; + + return ( +
+
+
Endpoint/Lambda
+
+ } + iconWrapperClass="" + childrenWrapperClass="left-auto right-auto" + > + { + addPageDropdownOptions.map((item, index) => ( + + )) + } + +
+
+ +
    + {endpoints.filter(e => e.type != "default").map((endpoint, index) => ( + <> +
  • onEndpointSelect(endpoint)} + > +
    + + + + + + + {endpoint.name || 'endpoint_' + index} +
    + + } + name={"Delete"} + onClick={(event) => { + event.stopPropagation(); + openModal(endpoint.id); + }} + /> + + +
  • + + ))} +
+ + + {showAddLambdaModal && lambdas && ( + setShowAddLambdaModal(false)} + > +
+
+
+ setShowAddLambdaModal(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Add Lambda +
+
+ + +
+
+
+ {lambdas.map((lambda, index) => ( +
handleAddLambda(lambda)} + > +
+ +
+
+

{lambda}

+
+
+ ))} +
+
+
+ )} + {isModalOpen && ( + item.id === deleteID))?.name} Endpoint/Lambda?`} + acceptText={`Delete`} + rejectText={`Cancel`} + /> + )} +
+ ); +} + +LeftPanel.propTypes = { + endpoints: PropTypes.arrayOf(PropTypes.object).isRequired, + onEndpointAdd: PropTypes.func.isRequired, + onEndpointDelete: PropTypes.func.isRequired, + onEndpointSelect: PropTypes.func.isRequired, +}; + +export default LeftPanel; diff --git a/src/components/ApiBuilder/MiddlePanel.tsx b/src/components/ApiBuilder/MiddlePanel.tsx new file mode 100644 index 0000000..019010d --- /dev/null +++ b/src/components/ApiBuilder/MiddlePanel.tsx @@ -0,0 +1,224 @@ +import React from "react"; + +const MiddlePanel = ({ endpoint, onSelectField, selectedField }) => { + const fields = [ + { + key: "name", + label: "Name", + description: "", + }, + { + key: "method", + label: "Method", + description: "", + }, + { + key: "route", + label: "Route", + description: "", + }, + { + key: "inputs", + label: "Inputs", + description: "", + }, + { + key: "logic", + label: "Route Logic", + description: "", + }, + { + key: "response", + label: "Route Response", + description: "", + }, + ]; + + return ( +
+
+
Components
+
+
+ {endpoint && ( +
+
+
    + {fields.map((field) => { + return ( +
  • onSelectField(field.key)} + > +
    + {field.label.toLowerCase() == "name" ? ( + + + + ) : field.label.toLowerCase() == "method" ? ( + + + + + + + + + + + ) : field.label.toLowerCase() == "route" ? ( + + + + + + ) : field.label.toLowerCase() == "route logic" ? ( + + + + ) : field.label.toLowerCase() == "route response" ? ( + + + + ) : ( + + + + + + + + + + + )} + + + {field.label} + +
    +
  • + ); + })} +
+
+
+ )} +
+ ); +}; + +export default MiddlePanel; diff --git a/src/components/ApiBuilder/RightPanel.tsx b/src/components/ApiBuilder/RightPanel.tsx new file mode 100644 index 0000000..1ee081e --- /dev/null +++ b/src/components/ApiBuilder/RightPanel.tsx @@ -0,0 +1,331 @@ +import React, { useState, useEffect } from "react"; +import EndPointLogic from "./EndpointLogic"; +import { DataTypes } from "@/utils/options/DataTypes"; +import EndpointResponse from "./EndpointResponse"; +import Toggle from "react-toggle"; + +const RightPanel = ({ + selectedEndpoint, + selectedField, + onFieldChange, + actions, + roles, +}) => { + const [fieldValue, setFieldValue] = useState(null); + const [numInputs, setNumInputs] = useState(1); + const [selectedCategory, setSelectedCategory] = useState(null); + const [selectedAction, setSelectedAction] = useState(null); + const [actionInputValues, setActionInputValues] = useState([]); + + useEffect(() => { + if (selectedEndpoint) { + setFieldValue(selectedEndpoint[selectedField]); + } + }, [selectedField]); + + const handleInputChange = (event) => { + const newValue = event.target.value; + setFieldValue(newValue); + onFieldChange(selectedField, newValue); + }; + + const handleCodeEditorInputChange = (value) => { + setFieldValue(value); + onFieldChange(selectedField, value); + }; + + const handleRouteProtectedInputChange = (event) => { + onFieldChange("protected", event.target.checked); + }; + + const handleAddAuthorizedRole = (event) => { + let roles = + Array.isArray(selectedEndpoint.authorizedRoles) && + selectedEndpoint.authorizedRoles.includes(event.target.value) + ? selectedEndpoint.authorizedRoles + : [...(selectedEndpoint.authorizedRoles ?? []), event.target.value]; + onFieldChange("authorizedRoles", roles); + event.target.value = ""; + }; + + const handleRemoveAuthorizedRole = (role) => { + let roles = selectedEndpoint.authorizedRoles.filter((r) => r != role); + onFieldChange("authorizedRoles", roles); + }; + + const handleAddInput = () => { + // Add a new input object to the inputs array + onFieldChange(`inputs`, [ + ...selectedEndpoint.inputs, + { + name: "", + type: "query", + rules: "", + }, + ]); + }; + + const handleResponseChange = (value) => { + onFieldChange(`response`, value); + }; + const handleRemoveInput = (inputIndex) => { + // Add a new input object to the inputs array + let remainingInputs = selectedEndpoint.inputs.filter( + (input, index) => inputIndex !== index + ); + onFieldChange(`inputs`, [...remainingInputs]); + }; + + const onInputsChange = (inputIndex, field, value) => { + selectedEndpoint.inputs = selectedEndpoint.inputs.map((input, index) => { + if (index === inputIndex) { + input[field] = value; + return input; + } + return input; + }); + onFieldChange(`inputs`, [...selectedEndpoint.inputs]); + }; + + const handleActionInputChange = (inputIndex, value) => { + setActionInputValues((prev) => { + prev[inputIndex] = value; + return prev; + }); + }; + + const handleActionInputSave = () => { + setFieldValue( + (prev) => + ` ${typeof prev !== "undefined" ? prev : "" + } \n ${selectedAction.template(...actionInputValues)} ` + ); + onFieldChange(selectedField, fieldValue); + setSelectedCategory(null); + setSelectedAction(null); + }; + + return ( +
+
+
Configuration
+
+ {/* +
+ + +
*/} +
+
+ +
+ {selectedEndpoint && ( +
+

{selectedField && selectedField.toUpperCase()}

+ {(selectedField === 'name' || selectedField === 'route') && ( + + )} + + {selectedField === "route" && ( + <> + + + +
+ {selectedEndpoint.protected &&
+
+ {selectedEndpoint.authorizedRoles?.map((role, index) => ( + + {role} + handleRemoveAuthorizedRole(role)} className='font-bold cursor-pointer'> + + + + + + ))} +
+ +
+ } + + )} + + {selectedField === "method" && ( + + )} + + {selectedField === "response" && ( + handleResponseChange(value)} + fieldValue={fieldValue} + endpoint={selectedEndpoint} + /> + )} + + {selectedField === "logic" && ( + + )} + + {selectedField === "functionStack" && ( + ; +}; + +export default BasicTextarea; diff --git a/src/components/BasicTextarea/index.ts b/src/components/BasicTextarea/index.ts new file mode 100644 index 0000000..c075925 --- /dev/null +++ b/src/components/BasicTextarea/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const BasicTextarea = lazy(() => import("./BasicTextarea")); + + \ No newline at end of file diff --git a/src/components/Calendar/Calendar.tsx b/src/components/Calendar/Calendar.tsx new file mode 100644 index 0000000..da028ef --- /dev/null +++ b/src/components/Calendar/Calendar.tsx @@ -0,0 +1,168 @@ +import { useState } from "react"; +import "@fullcalendar/react/dist/vdom"; +import { formatDate } from "@fullcalendar/core"; +import FullCalendar from "@fullcalendar/react"; +import dayGridPlugin from "@fullcalendar/daygrid"; +import timeGridPlugin from "@fullcalendar/timegrid"; +import interactionPlugin from "@fullcalendar/interaction"; +import listPlugin from "@fullcalendar/list"; +import { Modal } from "@/components/Modal/Modal"; +import ModalPrompt from "@/components/Modal/ModalPrompt"; +import "./calendar.css"; + +const Calendar = ({ defaulEvents, setEvents, isCalendarFullWidth = true }) => { + const [currentEvents, setCurrentEvents] = useState([]); + const [showAddEventmodal, setShowAddEventmodal] = useState(false); + const [showDeleteEventmodal, setShowDeleteEventmodal] = useState(false); + const [newEventName, setNewEventName] = useState(""); + const [currentSelectedDate, setCurrentSelectedDate] = useState(); + const [currentSelectedEvent, setCurrentSelectedEvent] = useState(); + + const handleDateClick = (selected) => { + if (selected.date && selected.dateStr) { + setCurrentSelectedDate(selected); + setShowAddEventmodal(true); + } + }; + + const handleEventsSet = (events) => { + setCurrentEvents(events); + if (setEvents) { + setEvents(events); + } + }; + + const handleAddModalSubmit = () => { + const calendarApi = currentSelectedDate?.view?.calendar; + calendarApi?.unselect(); + + if (newEventName) { + setShowAddEventmodal(false); + calendarApi?.addEvent({ + id: `${currentSelectedDate?.dateStr}-${newEventName}`, + title: newEventName, + start: currentSelectedDate.startStr, + end: currentSelectedDate.endStr, + allDay: currentSelectedDate.allDay, + }); + } + setNewEventName(""); + }; + + const handleEventClick = (selected) => { + setCurrentSelectedEvent(selected); + setShowDeleteEventmodal(true); + }; + + const handleDeletEventClick = () => { + currentSelectedEvent.event.remove(); + setShowDeleteEventmodal(false); + }; + + return ( + <> +
+
+ {/* CALENDAR SIDEBAR */} +
+
Events
+
    + {currentEvents.map((event) => ( +
  • +
    +
    {event.title}
    +

    + {formatDate(event.start, { + year: "numeric", + month: "short", + day: "numeric", + })} +

    +
    +
  • + ))} +
+
+ + {/* CALENDAR */} +
+ handleEventsSet(events)} + initialEvents={defaulEvents} + /> +
+
+
+ + {showAddEventmodal && ( + setShowAddEventmodal(false)} + modalHeader={true} + classes={"w-1/2"} + > +
+ setNewEventName(e.target.value)} + /> + +
+
+ )} + + {showDeleteEventmodal && ( + { + setShowDeleteEventmodal(false); + }} + message="Are you sure you want to delete this event?" + title="Delete Event" + loading={false} + actionHandler={handleDeletEventClick} + /> + )} + + ); +}; + +export default Calendar; diff --git a/src/components/Calendar/calendar.css b/src/components/Calendar/calendar.css new file mode 100644 index 0000000..b4defba --- /dev/null +++ b/src/components/Calendar/calendar.css @@ -0,0 +1,3 @@ +.calendar-full-width .fc.fc-media-screen.fc-direction-ltr{ + width:100%; +} \ No newline at end of file diff --git a/src/components/Calendar/index.ts b/src/components/Calendar/index.ts new file mode 100644 index 0000000..ce3c01b --- /dev/null +++ b/src/components/Calendar/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const Calendar = lazy(() => import("./Calendar")); + \ No newline at end of file diff --git a/src/components/CameraToUpload/CameraToUpload.tsx b/src/components/CameraToUpload/CameraToUpload.tsx new file mode 100644 index 0000000..d8792e3 --- /dev/null +++ b/src/components/CameraToUpload/CameraToUpload.tsx @@ -0,0 +1,298 @@ +import React, { memo, useEffect, useRef, useState } from "react"; +import MkdSDK from "@/utils/MkdSDK"; +import { Spinner } from "@/assets/svgs"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; + +const sdk = new MkdSDK(); + +const CameraToUpload = ({ onSave = undefined, uploadSuccess = undefined }) => { + const { dispatch, state } = React.useContext(AuthContext); + const { dispatch: globalDispatch, state: globalState } = + React.useContext(GlobalContext); + + const photoTrayRef = useRef(null); + const videoRef = useRef(null); + const canvasRef = useRef(null); + const [submitLoading, setSubmitLoading] = useState(false); + const [showCamera, setShowCamera] = useState(false); + const [useFrontCam, setUseFrontCam] = useState(true); + const [photos, setPhotos] = useState([]); + + const constraints = { + video: { + facingMode: { exact: useFrontCam ? "user" : "environment" }, + advanced: [{ zoom: 1 }], + }, + }; + + const handleCapture = () => { + const video = videoRef.current; + const canvas = canvasRef.current; + const aspectRatio = video.videoWidth / video.videoHeight; + + // Calculate the aspect ratio of the video + let canvasWidth = video.offsetWidth; + let canvasHeight = canvasWidth / aspectRatio; + + if (canvasHeight > video.offsetHeight) { + canvasHeight = video.offsetHeight; + canvasWidth = canvasHeight * aspectRatio; + } + + // Set the canvas size based on the aspect ratio of the video + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + // Draw the current video frame on the canvas + const context = canvas.getContext("2d"); + context.drawImage(video, 0, 0, canvasWidth, canvasHeight); + + // Convert the canvas data to a blob + canvas.toBlob((blob) => { + // Upload the blob to the server + setPhotos((prev) => [...prev, blob]); + if (!photos.length) { + photoTrayRef.current.style.maxHeight = `200px`; + } + }); + }; + + const handleStream = (stream) => { + const video = videoRef.current; + video.style.display = "block"; + video.srcObject = stream; + video.play(); + }; + async function uploadFunction(formData) { + try { + let uploadResult = await sdk.uploadImage(formData); + + if (!uploadResult.error) { + return uploadResult?.url; // Return the response data from the server + } + } catch (error) { + throw new Error(error.message); + } + } + + const handleUpload = async () => { + if (!uploadSuccess) { + throw new Error("uploadSuccess is not a function"); + } + setSubmitLoading(true); + try { + if (photos && photos.length) { + const uploadPromises = photos.map(async (item) => { + let formData = new FormData(); + formData.append("file", item); + + // Perform the upload operation for 'item' and return the result + return uploadFunction(formData); // Replace 'uploadFunction' with your actual upload logic + }); + const uploadResults = await Promise.all(uploadPromises); + // Process uploadResults if needed + showToast(globalDispatch, "Upload Successful", 5000, "success"); + uploadSuccess(uploadResults); + } + setSubmitLoading(false); + } catch (error) { + setSubmitLoading(false); + tokenExpireError( + dispatch, + error?.response?.data?.message + ? error?.response?.data?.message + : error?.message + ); + showToast( + globalDispatch, + error?.response?.data?.message + ? error?.response?.data?.message + : error?.message, + 5000, + "error" + ); + // Handle errors + } + }; + + const handleSave = () => { + if (onSave) { + onSave(photos); + } + }; + + const handleError = (error) => { + console.error("Error accessing camera:", error); + }; + + const startCapture = async () => { + try { + // Request access to the camera + const stream = await navigator.mediaDevices.getUserMedia(constraints); + + setShowCamera(true); + // Display the camera feed on the video element + handleStream(stream); + } catch (error) { + handleError(error); + } + }; + + const stopCapture = () => { + // Stop all tracks in the stream + if (videoRef.current.srcObject) { + videoRef.current.srcObject.getTracks().forEach((track) => track.stop()); + } + setPhotos(() => []); + setShowCamera(false); + // Release the camera resources + videoRef.current.srcObject = null; + }; + const removeItem = (index) => { + const tempPhotos = [...photos]; + tempPhotos.splice(index, 1); + setPhotos(() => [...tempPhotos]); + }; + + useEffect(() => { + if (photos.length === 0) { + photoTrayRef.current.style.maxHeight = null; + } + }, [photos.length]); + + return ( + <> +
+
+
+ Take picture now + + Switch to Mobile to take picture + +
+
startCapture()} + className={`flex h-full w-[5.625rem] min-w-[5.625rem] items-center justify-center rounded-[0rem_1.25rem] bg-blue-600 md:hidden`} + > + camera +
+
+

+
+ +
+
+
+
+ + + ); +}; + +export default memo(CameraToUpload); diff --git a/src/components/CameraToUpload/index.ts b/src/components/CameraToUpload/index.ts new file mode 100644 index 0000000..984245c --- /dev/null +++ b/src/components/CameraToUpload/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const CameraToUpload = lazy(() => import("./CameraToUpload")); + \ No newline at end of file diff --git a/src/components/CharacterSelect.tsx b/src/components/CharacterSelect.tsx deleted file mode 100644 index 74629bc..0000000 --- a/src/components/CharacterSelect.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import { characters } from '../data/characters'; -import { Character } from '../types'; - -interface CharacterSelectProps { - selectedCharacter: Character | null; - onSelect: (character: Character) => void; -} - -export function CharacterSelect({ selectedCharacter, onSelect }: CharacterSelectProps) { - return ( -
- {characters.map((character) => ( -
onSelect(character)} - className={` - relative rounded-lg overflow-hidden cursor-pointer - transform transition-all duration-200 - ${selectedCharacter?.id === character.id - ? 'ring-2 ring-blue-500 scale-105' - : 'hover:scale-105' - } - `} - > - {character.name} -
-

{character.name}

-
-
- ))} -
- ); -} \ No newline at end of file diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx new file mode 100644 index 0000000..64389c2 --- /dev/null +++ b/src/components/Chat/Chat.tsx @@ -0,0 +1,509 @@ +import React from "react"; +import MkdSDK from "@/utils/MkdSDK"; +import moment from "moment"; +import { ImagePreviewModal } from "@/components/ImagePreviewModal"; +import { CreateNewRoomModal } from "@/components/CreateNewRoomModal"; +import { + UserCircleIcon, + PaperAirplaneIcon, + ArrowLeftIcon, + PaperClipIcon, +} from "@heroicons/react/20/solid"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import InputEmoji from "react-input-emoji"; +import { renderName } from "@/components/CreateNewRoomModal"; +const abortController = new AbortController(); + +const Chat = ({ roles = [] }) => { + const { state } = React.useContext(AuthContext); + const { dispatch } = React.useContext(AuthContext); + const [rooms, setRooms] = React.useState([]); + const [messages, setMessages] = React.useState([]); + const [chatId, setChatId] = React.useState(); + const otherUserId = React.useRef(); + const currentRooms = React.useRef(); + const inputRef = React.useRef(null); + const [message, setMessage] = React.useState(""); + const [roomId, setRoomId] = React.useState(); + const [file, setFile] = React.useState(null); + const [previewModal, showPreviewModal] = React.useState(false); + const [screenSize, setScreenSize] = React.useState(window.innerWidth); + const [showContacts, setShowContacts] = React.useState(true); + const [createRoom, setCreateRoom] = React.useState(false); + const [filteredRooms, setFilteredRooms] = React.useState([]); + + function setDimension(e) { + if (e.currentTarget.innerWidth > 1024) { + setShowContacts(true); + } + setScreenSize(e.currentTarget.innerWidth); + } + + let sdk = new MkdSDK(); + + const handleClick = () => { + inputRef.current.click(); + }; + + const cancelFileUpload = () => { + showPreviewModal(false); + setFile(null); + inputRef.current.value = ""; + }; + + const formatDate = (time) => { + let currentTime = moment(new Date()); + let messageDate = moment(time); + if (currentTime.diff(messageDate, "days") > 1) { + return moment(messageDate).format("Do MMMM"); + } else { + return moment(messageDate).format("hh:mm A"); + } + }; + + const handleFileUpload = async (e) => { + e.preventDefault(); + const formData = new FormData(); + for (let i = 0; i < file.length; i++) { + formData.append("file", file[i]); + } + try { + const upload = await sdk.uploadImage(formData); + await sendImageAsMessage(upload); + } catch (err) { + console.log(err); + } + }; + + async function getRooms(filter) { + try { + if (filter) { + return setFilteredRooms( + rooms.filter((user) => + `${renderName(user).toLowerCase()}`.includes(filter.toLowerCase()) + ) + ); + } + + const chats = await sdk.getMyRoom(); + if (chats && chats.list && chats.list[0]) { + setRooms(chats.list); + setFilteredRooms(chats.list); + currentRooms.current = chats.list; + } + } catch (err) { + console.log("Error:", err); + } + } + + async function createNewRoom(otherUser) { + try { + const createdRoom = await sdk.createRoom({ + user_id: state.user, + other_user_id: otherUser.id, + }); + let newRoom = { + chat_id: createdRoom.chat_id, + create_at: new Date(), + email: otherUser.email, + first_name: otherUser.first_name, + id: createdRoom.room_id, + last_name: otherUser.last_name, + other_user_id: otherUser.id, + other_user_update_at: new Date(), + photo: otherUser.photo, + unread: 0, + update_at: new Date(), + user_id: state.user, + user_update_at: new Date(), + }; + + const updatedRoomList = [newRoom, ...rooms]; + setRooms(updatedRoomList); + setFilteredRooms(updatedRoomList); + currentRooms.current = updatedRoomList; + setCreateRoom(false); + + if (document.getElementById(`user-${otherUser.id}`)) { + document.getElementById(`user-${otherUser.id}`).click(); + } else { + setTimeout(() => { + document.querySelector(".container-chat").firstChild.click(); + }, 200); + } + } catch (err) { + setCreateRoom(false); + document.getElementById(`user-${otherUser.id}`).click(); + } + } + + async function getChats(room_id, chat_id) { + try { + setRoomId(room_id); + setChatId(chat_id); + let date = new Date().toISOString().split("T")[0]; + const messages = await sdk.getChats(room_id, chat_id, date); + if (messages && messages.model) { + setMessages(messages.model.reverse()); + } + } catch (err) { + console.log("Error:", err); + } + } + + async function sendMessage() { + try { + let date = new Date().toISOString().split("T")[0]; + await sdk.postMessage({ + room_id: roomId, + chat_id: chatId, + user_id: state.user, + message, + date, + }); + let newMessageObj = { + chat: { + message: message, + user_id: state.user, + is_image: false, + timeStamp: new Date(), + }, + }; + const updatedMessages = [...messages, newMessageObj]; + setMessages(updatedMessages); + setMessage(""); + } catch (err) { + console.log("Error:", err); + } + } + + async function sendImageAsMessage(upload) { + try { + let date = new Date().toISOString().split("T")[0]; + await sdk.postMessage({ + room_id: roomId, + chat_id: chatId, + user_id: state.user, + message: upload.url, + date, + is_image: true, + }); + let newMessageObj = { + message: upload.url, + user_id: state.user, + is_image: true, + timeStamp: new Date(), + }; + const updatedMessages = [...messages, newMessageObj]; + setMessages(updatedMessages); + showPreviewModal(false); + setFile(null); + inputRef.current.value = ""; + setMessage(""); + } catch (err) { + console.log("Error:", err); + } + } + + async function startPooling() { + try { + const pool = await sdk.startPooling(state.user); + if (pool.message) { + let newMessageObj = { + message: pool.message, + user_id: pool.user_id, + is_image: false, + timeStamp: new Date(), + }; + if (pool.user_id === otherUserId.current) { + setMessages((prevMessages) => [...prevMessages, newMessageObj]); + setTimeout(async () => { + await startPooling(); + }, 2000); + } else { + setTimeout(async () => { + await startPooling(); + }, 1000); + } + } else { + setTimeout(async () => { + startPooling(); + }, 1000); + } + } catch (err) { + tokenExpireError(dispatch, err.message); + if (err.message === "TOKEN_EXPIRED") + window.location.replace(`/${state.role}/login/`); + else + setTimeout(async () => { + startPooling(); + }, 500); + } + } + + const pollMessages = async () => { + try { + const poll = await sdk.startPooling( + localStorage.getItem("user"), + abortController.signal + ); + if (poll.message) { + await getChats(); + } + } catch (error) { + console.log(error); + } finally { + if (!abortController.signal.aborted) { + pollMessages(); + } + } + }; + + React.useEffect(() => { + (async function () { + await getRooms(); + })(); + }, []); + + React.useEffect(() => { + getChats(); + pollMessages(); + return () => { + abortController.abort(); + }; + }, []); + + React.useEffect(() => { + window.addEventListener("resize", setDimension); + + return () => { + window.removeEventListener("resize", setDimension); + }; + }, [screenSize]); + + return ( +
+
+
+
+

Chat

+
+
+ {showContacts && ( + <> +
+ +
+
+
+ getRooms(e.target.value)} + /> +
+ +
+ {filteredRooms && + filteredRooms.map((room, idx) => ( +
{ + getChats(room.id, room.chat_id); + otherUserId.current = room.other_user_id; + otherUserId.currentRoom = room; + if (screenSize < 1024) { + setShowContacts(false); + } + }} + > +
+
+ {room.photo ? ( + user-photo + ) : ( + + )} +
+
+
+
+ + {renderName(room)} + +
+
+
+
+ + {formatDate(room.update_at)} + +
+ {room.unread > 0 && ( +
+ + {room.unread} + +
+ )} +
+
+ ))} +
+
+ + )} + + {screenSize > 1023 || (screenSize < 1024 && !showContacts) ? ( +
+ {otherUserId?.current ? ( +
+
+

+ setShowContacts(true)} + > + + + Chatting with{" "} + {`${renderName( + otherUserId.currentRoom + )}`} +

+
+ + {messages && ( +
+ {messages.map((message, idx) => ( +
+ {message?.chat?.user_id !== state.user && ( +
+
+ +
+
+ )} +
+
+ {message.is_image ? ( + + ) : ( +

+ {message?.chat?.message} +

+ )} +
+
+ + {moment(message?.chat?.timestamp).format( + "hh:mm A" + )} + +
+
+
+ ))} +
+ )} + +
+
+
+ +
+
+
+ + { + setFile(e.target.files); + showPreviewModal(true); + }} + /> + + +
+
+ +
+
+
+
+
+ ) : ( +
+ Select a Chat to view +
+ )} +
+ ) : null} +
+
+
+ {previewModal && file ? ( + + ) : null} + {createRoom && ( + + )} +
+ ); +}; + +export default Chat; diff --git a/src/components/Chat/index.ts b/src/components/Chat/index.ts new file mode 100644 index 0000000..d2c53b0 --- /dev/null +++ b/src/components/Chat/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const Chat = lazy(() => import("./Chat")); + \ No newline at end of file diff --git a/src/components/ChatBot/Chat.tsx b/src/components/ChatBot/Chat.tsx new file mode 100644 index 0000000..a85821f --- /dev/null +++ b/src/components/ChatBot/Chat.tsx @@ -0,0 +1,229 @@ +import { useContext, useEffect, useRef, useState } from "react"; +import { FiSend } from "react-icons/fi"; +import { BsPlusLg } from "react-icons/bs"; +import { RxHamburgerMenu } from "react-icons/rx"; + +import Message from "./Message"; +import { homePage } from "./ChatUtils"; + +import MkdSDK from "@/utils/MkdSDK"; +import { GlobalContext } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; + +const Chat = (props) => { + const { toggleComponentVisibility, index, currentRoom } = props; + + const { state, dispatch } = useContext(GlobalContext); + const { dispatch: authDispatch } = useContext(AuthContext); + const [isLoading, setIsLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + const [showEmptyChat, setShowEmptyChat] = useState(true); + const [conversation, setConversation] = useState([]); + const [message, setMessage] = useState(""); + const [generating, setGenerating] = useState(false); + const bottomOfChatRef = useRef(null); + + let sdk = new MkdSDK(); + + useEffect(() => { + if (bottomOfChatRef.current) { + bottomOfChatRef.current.scrollIntoView({ behavior: "smooth" }); + } + }, [conversation]); + + const sendMessage = async (e) => { + // Don't send empty messages + if (message.length < 1) { + setErrorMessage("Please enter a message."); + return; + } else { + setErrorMessage(""); + dispatch({ + type: "SETROOM", + payload: { position: props.index, value: message }, + }); + } + + setIsLoading(true); + + // Add the message to the conversation + setConversation([ + ...conversation, + { content: message, role: "user", content2: null, role2: "system" }, + ]); + + // Clear the message & remove empty chat + setMessage(""); + setShowEmptyChat(false); + + try { + setGenerating(true); + const response = await sdk.chatGPT(message); + + if (response.ok) { + const data = await response.json(); + setGenerating(false); + + // Add the message to the conversation + setConversation([ + ...conversation, + { + content: message, + role: "user", + content2: data.Answer, + role2: "system", + }, + ]); + } else { + console.error(response); + setGenerating(false); + + setErrorMessage(response.statusText); + } + + setIsLoading(false); + } catch (error) { + console.error(error); + setGenerating(false); + setErrorMessage(error.message); + tokenExpireError( + authDispatch, + error?.response?.data?.messsage + ? error?.response?.data?.messsage + : error?.message + ); + setIsLoading(false); + } + }; + + const handleKeypress = (e) => { + // It's triggers by pressing the enter key + if (e.keyCode == 13 && !e.shiftKey) { + sendMessage(e); + e.preventDefault(); + } + }; + + return ( +
+
+ +

New chat

+ +
+
+
+
+
+ {!showEmptyChat && conversation.length > 0 ? ( +
+ +
+
+
+ ) : null} + {showEmptyChat ? ( +
+

+ ChatGPT +

+
+ {homePage.map((item, index) => ( +
+
+ + {item.icon} + +

+ {item.title} +

+
+
+ {item.details.map((details, index) => ( +
+ {details} +
+ ))} +
+
+ ))} +
+
+ ) : null} +
+
+
+
+
+
+
+
+ + + ) + + case "image": + return ( + <> + preview + + + ) + + case "number": + return ( + setContentValue(e.target.value)} + defaultValue={contentValue} + /> + ) + + case "team-list": + return ( + + ) + + case "image-list": + return ( + + ) + + case "captioned-image-list": + return ( + + ) + + case "kvp": + return ( + + ) + + default: + break; + } +} + +export default DynamicContentType; + +const ImageList = ({ contentValue, setContentValue }) => { + let itemsObj = [ + { key: '', value_type: 'image', value: null } + ]; + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } catch (err) { + console.error(err); + } + } + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + + } + + return ( +
+ {items.map((item, index) =>
+ preview +
+ + +
+ +
) + } + +
+ + ) +} + +const CaptionedImageList = ({ setContentValue, contentValue }) => { + let itemsObj = [ + { key: '', value_type: 'image', value: null, caption: '' } + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } catch (err) { + console.error(err); + } + } + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleCaptionChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.caption = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map((item, index) =>
+ preview +
+ + +
+ + +
) + } + +
+ + ) +} +const TeamList = ({ setContentValue, contentValue }) => { + let itemsObj = [ + { name: '', image: null, title: '' } + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.image = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } catch (err) { + console.error(err); + } + } + + const handleNameChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.name = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleTitleChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.title = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map((item, index) =>
+ + {/*
*/} + + + preview + + {/*
*/} + + +
) + } + +
+ + ) +} +const KeyValuePair = ({ setContentValue, contentValue }) => { + let itemsObj = [ + { key: '', value_type: 'text', value: '' } + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + + const [items, setItems] = React.useState(itemsObj); + const valueTypeMap = [ + { + key: "text", + value: "Text" + }, + { + key: "number", + value: "Number" + }, + { + key: "json", + value: "JSON Object" + }, + { + key: "url", + value: "URL" + } + ] + + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleValueChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleValueTypeChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value_type = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map((item, index) =>
+ + + + + +
) + } + +
+ + ) +} + + diff --git a/src/components/DynamicContentType/index.ts b/src/components/DynamicContentType/index.ts new file mode 100644 index 0000000..a1668da --- /dev/null +++ b/src/components/DynamicContentType/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const DynamicContentType = lazy(() => import("./DynamicContentType")); + + \ No newline at end of file diff --git a/src/components/EditWireframeTabs/EditWireframeTab/EditWireframeTab.tsx b/src/components/EditWireframeTabs/EditWireframeTab/EditWireframeTab.tsx new file mode 100644 index 0000000..6e136a5 --- /dev/null +++ b/src/components/EditWireframeTabs/EditWireframeTab/EditWireframeTab.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +const EditWireframeTab = ({ handleClick, activeTab, tab }) => { + return ( +
handleClick(tab)} + > + {tab} +
+ ); +}; + +export default EditWireframeTab; diff --git a/src/components/EditWireframeTabs/EditWireframeTab/index.ts b/src/components/EditWireframeTabs/EditWireframeTab/index.ts new file mode 100644 index 0000000..8cc82ef --- /dev/null +++ b/src/components/EditWireframeTabs/EditWireframeTab/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const EditWireframeTab = lazy(() => import("./EditWireframeTab")); diff --git a/src/components/EditWireframeTabs/EditWireframeTabs.tsx b/src/components/EditWireframeTabs/EditWireframeTabs.tsx new file mode 100644 index 0000000..7f69055 --- /dev/null +++ b/src/components/EditWireframeTabs/EditWireframeTabs.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { EditWireframeTab } from "./EditWireframeTab"; +import { EditWireframeTabTypes } from "@/utils/constants"; + +const EditWireframeTabs = ({ handleClick, activeTab, filterArr }) => { + return ( +
+ {Object.keys(EditWireframeTabTypes).map((tab, tabIndex) => ( + + ))} +
+ ); +}; + +export default EditWireframeTabs; diff --git a/src/components/EditWireframeTabs/index.ts b/src/components/EditWireframeTabs/index.ts new file mode 100644 index 0000000..73fc263 --- /dev/null +++ b/src/components/EditWireframeTabs/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const EditWireframeTabs = lazy(() => import("./EditWireframeTabs")); diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx new file mode 100644 index 0000000..e2bb471 --- /dev/null +++ b/src/components/Editor/Editor.tsx @@ -0,0 +1,48 @@ +import React, { useState } from "react"; +import ReactQuill from "react-quill"; +import { EditorToolbars } from "."; +import { formats, modules } from "./EditorToolbars"; + +const Editor = ({ + setValue, + errors, + name, + placeholder = "Write something awesome...", + initialContent = "", +}) => { + const [content, setContent] = useState(initialContent); + const editorStyle = { + // maxheight: '500px', + // minheight: '500px', + height: "500px", + // overFlow: 'auto', + + // set the height to 500 pixels + }; + const onSetContent = (content) => { + setContent(content); + setValue(name, content); + }; + + return ( + <> + + onSetContent(content)} + placeholder={placeholder} + modules={modules} + formats={formats} + style={editorStyle} + /> + {errors && errors?.content && ( +

+ {errors?.content?.message} +

+ )} + + ); +}; + +export default Editor; diff --git a/src/components/Editor/EditorToolbars.tsx b/src/components/Editor/EditorToolbars.tsx new file mode 100644 index 0000000..b2b5b69 --- /dev/null +++ b/src/components/Editor/EditorToolbars.tsx @@ -0,0 +1,160 @@ + +import React from "react"; +import { Quill } from "react-quill"; + +// Custom Undo button icon component for Quill editor. You can import it directly +// from 'quill/assets/icons/undo.svg' but I found that a number of loaders do not +// handle them correctly +const CustomUndo = () => ( + + + + +); + +// Redo button icon component for Quill editor +const CustomRedo = () => ( + + + + +); + +// Undo and redo functions for Custom Toolbar +function undoChange () { + this.quill.history.undo(); +} +function redoChange () { + this.quill.history.redo(); +} + +// Add sizes to whitelist and register them +const Size = Quill.import( "formats/size" ); +Size.whitelist = [ "extra-small", "small", "medium", "large" ]; +Quill.register( Size, true ); + +// Add fonts to whitelist and register them +const Font = Quill.import( "formats/font" ); +Font.whitelist = [ + "arial", + "comic-sans", + "courier-new", + "georgia", + "helvetica", + "lucida" +]; +Quill.register( Font, true ); + +// Modules object for setting up the Quill editor +export const modules = { + toolbar: { + container: "#toolbar", + handlers: { + undo: undoChange, + redo: redoChange + } + }, + history: { + delay: 500, + maxStack: 100, + userOnly: true + } +}; + +// Formats objects for setting up the Quill editor +export const formats = [ + "header", + "font", + "size", + "bold", + "italic", + "underline", + "align", + "strike", + "script", + "blockquote", + "background", + "list", + "bullet", + "indent", + "link", + "image", + "color", + "code-block" +]; + +// Quill Toolbar component +const QuillToolbar = () => ( +
+ + + + + + +
- ); -} \ No newline at end of file diff --git a/src/components/InfiniteScroll/InfiniteScroll.tsx b/src/components/InfiniteScroll/InfiniteScroll.tsx new file mode 100644 index 0000000..52e5c9e --- /dev/null +++ b/src/components/InfiniteScroll/InfiniteScroll.tsx @@ -0,0 +1,97 @@ + +import React, { useCallback, useEffect, useRef, memo, useState } from 'react'; + +// example below this file + +const InfiniteScroll = ( { + data, + children, + height, + next, + pageSize, + nextCursor, + className, + setPageSize, + setNextCursor, + currentCursor, + setData +} ) => { + const [ initialized, setInitialized ] = useState( false ) + + const scrollRef = useInfiniteScroll( () => { + // logic for loading more data here + if ( nextCursor === 0 ) { + return + } else { + next( true, nextCursor ) + } + } ); + + const onUpdatePageSize = useCallback( ( size ) => { + + setPageSize( size ) + setData( () => [] ) + + setNextCursor( () => null ) + setInitialized( true ) + }, [ initialized, pageSize, data, nextCursor ] ) + + useEffect( () => { + if ( !initialized ) { + next( initialized, null ) + setInitialized( true ) + } + }, [ initialized ] ); + + return ( +
+ +
+ { children } +
+
+ +
+
+ ); +} + +export default memo( InfiniteScroll ) + +function useInfiniteScroll ( callback ) { + const scrollRef = useRef( null ); + + useEffect( () => { + const handleScroll = () => { + const scrollElement = scrollRef.current; + if ( scrollElement.scrollTop + scrollElement.clientHeight >= scrollElement.scrollHeight ) { + callback(); + } + }; + + const scrollElement = scrollRef.current; + scrollElement.addEventListener( 'scroll', handleScroll ); + + return () => { + scrollElement.removeEventListener( 'scroll', handleScroll ); + }; + }, [ callback ] ); + + + return scrollRef; +} + + + diff --git a/src/components/InfiniteScroll/index.ts b/src/components/InfiniteScroll/index.ts new file mode 100644 index 0000000..000b7ab --- /dev/null +++ b/src/components/InfiniteScroll/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const InfiniteScroll = lazy(() => import("./InfiniteScroll")); + + \ No newline at end of file diff --git a/src/components/InteractiveButton/InteractiveButton.module.css b/src/components/InteractiveButton/InteractiveButton.module.css new file mode 100644 index 0000000..e9e80c0 --- /dev/null +++ b/src/components/InteractiveButton/InteractiveButton.module.css @@ -0,0 +1,30 @@ +.button { + position: relative; + border: none; + color: #ffffff; + text-align: center; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + text-decoration: none; + overflow: hidden; + cursor: pointer; +} +.button:after { + content: ""; + background: #4f46e5; + display: block; + position: absolute; + padding-top: 300%; + padding-left: 350%; + margin-left: -20px !important; + margin-top: -120%; + opacity: 0; + transition: all 0.8s; +} + +.button:active:after { + padding: 0; + margin: 0; + opacity: 1; + transition: 0s; +} diff --git a/src/components/InteractiveButton/InteractiveButton.tsx b/src/components/InteractiveButton/InteractiveButton.tsx new file mode 100644 index 0000000..9bb62a3 --- /dev/null +++ b/src/components/InteractiveButton/InteractiveButton.tsx @@ -0,0 +1,73 @@ +import { memo, ReactNode, Ref, useId, useState } from "react"; +import classes from "./InteractiveButton.module.css"; +import { LoaderTypes, MkdLoader } from "@/components/MkdLoader"; + +interface InteractiveButtonProps { + loading?: boolean; + animate?: boolean; + disabled?: boolean; + children: ReactNode; + type?: "button" | "submit" | "reset"; + className?: string; + loaderclasses?: string; + onClick?: () => void; + color?: string; + loaderType?: LoaderTypes; + buttonRef?: Ref; + size?: number +} + +const InteractiveButton = ({ + loading = false, + animate = false, + disabled, + children, + type = "button", + className, + loaderclasses, + onClick, + color = "#ffffff", + loaderType = LoaderTypes.BEAT, + buttonRef = null, + size= 10 +}: InteractiveButtonProps) => { + const id = useId(); + + const [animated, setAnimated] = useState(false); + + const onClickHandle = () => { + if (onClick) { + onClick(); + } + if (animate) { + setAnimated(true); + } + }; + return ( + + ); +}; + +export default memo(InteractiveButton); diff --git a/src/components/InteractiveButton/index.ts b/src/components/InteractiveButton/index.ts new file mode 100644 index 0000000..388d80d --- /dev/null +++ b/src/components/InteractiveButton/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const InteractiveButton = lazy(() => import("./InteractiveButton")); + + \ No newline at end of file diff --git a/src/components/InteractiveMap/InteractiveMap.tsx b/src/components/InteractiveMap/InteractiveMap.tsx new file mode 100644 index 0000000..f6046ae --- /dev/null +++ b/src/components/InteractiveMap/InteractiveMap.tsx @@ -0,0 +1,58 @@ +import React, { useState } from 'react'; +import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api'; + +const InteractiveMap = ({ cards }) => { + const [selectedCardIndex, setSelectedCardIndex] = useState(null); + + const handleMarkerClick = (index) => { + setSelectedCardIndex(index); + }; + + const mapContainerStyle = { + width: '60%', + height: '700px', + }; + + const defaultCenter = { lat: 0, lng: 0 }; // Update with your desired center +// AIzaSyDeZ9Lr2B3mPGfzQBMbqcS9gGugI2F-bSM +// AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg +// https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=AIzaSyDeZ9Lr2B3mPGfzQBMbqcS9gGugI2F-bSM + return ( +
+
+ {cards.map((card, index) => ( +
+

Card {index + 1}

+
+

Price: ${card.price}

+

Latitude: {card.latitude}

+

Longitude: {card.longitude}

+
+
+ ))} +
+ + + {cards.map((card, index) => ( + handleMarkerClick(index)} + label={card.price.toString()} // Display price as marker label + // Add more properties for customization (e.g., icon) + /> + ))} + + +
+ ); +}; + +export default InteractiveMap; diff --git a/src/components/InteractiveMap/index.ts b/src/components/InteractiveMap/index.ts new file mode 100644 index 0000000..fe2a099 --- /dev/null +++ b/src/components/InteractiveMap/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const InteractiveMap = lazy(() => import("./InteractiveMap")); + \ No newline at end of file diff --git a/src/components/LandingPage/HowItWorks.tsx b/src/components/LandingPage/HowItWorks.tsx new file mode 100644 index 0000000..73b380b --- /dev/null +++ b/src/components/LandingPage/HowItWorks.tsx @@ -0,0 +1,152 @@ +export default function HowItWorks() { + return ( + <> +
+
+

How it works

+

+ One platform for all your dev needs +

+
+ +
+
+
+ + + + +
+
Wireframes
+

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate augue. + Sed sit amet mi tortor. Praesent lacus lectus, commodo vel + suscipit sit amet, imperdiet sed leo. +

+
+ +
+
+ + + + + + +
+
Working prototypes
+

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate augue. + Sed sit amet mi tortor. Praesent lacus lectus, commodo vel + suscipit sit amet, imperdiet sed leo. +

+
+
+
+ + + + +
+
Code exports
+

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate augue. + Sed sit amet mi tortor. Praesent lacus lectus, commodo vel + suscipit sit amet, imperdiet sed leo. +

+
+
+
+ + + + + +
+
API build (by AI ✨)
+

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate augue. + Sed sit amet mi tortor. Praesent lacus lectus, commodo vel + suscipit sit amet, imperdiet sed leo. +

+
+
+
See first hand 👀
+

+ Try Baas for 7 days - no strings attached. +

+ + + (No credit card required) + +
+
+
+ + ); +} diff --git a/src/components/LandingPage/LandingCta.tsx b/src/components/LandingPage/LandingCta.tsx new file mode 100644 index 0000000..e1addee --- /dev/null +++ b/src/components/LandingPage/LandingCta.tsx @@ -0,0 +1,32 @@ +import SpiralArrow from "@/assets/svgs/SpiralArrow"; + +export default function LandingCta() { + return ( +
+
+
+

Give it a try - risk free!

+

+ See for yourself how Baas can speed up your work 10x 🔥. Aenean diam + nisl, gravida varius ligula sed, efficitur sagittis mi. Duis at + justo eu dui hendrerit finibus sit amet sed lorem. +

+
+
+ +
+
+ +

+ (No credit card required) +

+
+
+
+ ); +} diff --git a/src/components/LandingPage/LandingDetailView.tsx b/src/components/LandingPage/LandingDetailView.tsx new file mode 100644 index 0000000..08b1503 --- /dev/null +++ b/src/components/LandingPage/LandingDetailView.tsx @@ -0,0 +1,177 @@ +export default function LandingDetailView() { + return ( +
+
+

Features

+

+ Detailed view on key features +

+
+ +
+
+
+
+
+ + + + + + +
+
Feature name
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+
+
+
+ + + + +
+
Feature name
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. +

+
+
+
+
+
+
+ + + + +
+
Feature name
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+
+
+
+ + + + +
+
Feature name
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+
+ ); +} diff --git a/src/components/LandingPage/LandingFaq.tsx b/src/components/LandingPage/LandingFaq.tsx new file mode 100644 index 0000000..3ff93a7 --- /dev/null +++ b/src/components/LandingPage/LandingFaq.tsx @@ -0,0 +1,80 @@ +export default function LandingFaq() { + return ( +
+
+

Quick answers

+

+ Frequently asked questions +

+
+ +
+ {[1, 2, 3, 4, 5, 6].map((item) => ( +
+
+ + + + + + + + + +
+
+
Question example one?
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+ ))} +
+ +
+

+ Still got questions? We're here to help 🤙 +

+ +
+
+ ); +} diff --git a/src/components/LandingPage/LandingFeature.tsx b/src/components/LandingPage/LandingFeature.tsx new file mode 100644 index 0000000..72df752 --- /dev/null +++ b/src/components/LandingPage/LandingFeature.tsx @@ -0,0 +1,61 @@ +export default function LandingFeature() { + return ( + <> +
+
+

Tagline

+

+ One platform for all your dev needs +

+

+ Nunc scelerisque accumsan ante vestibulum consequat. Quisque justo + urna, rhoncus in erat ac, lobortis eleifend nulla. +

+
+
+
+
+
+
+
Feature preview example one
+ +

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, + commodo vel suscipit sit amet, imperdiet sed leo. +

+
+
+
Feature preview example one
+ +

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, + commodo vel suscipit sit amet, imperdiet sed leo. +

+
+
+
Feature preview example one
+

+ Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, + commodo vel suscipit sit amet, imperdiet sed leo. +

+
+
+
+
+
+ Baas Feature wireframe +
+
+
+
+
+ + ); +} diff --git a/src/components/LandingPage/LandingInfo.tsx b/src/components/LandingPage/LandingInfo.tsx new file mode 100644 index 0000000..d872b46 --- /dev/null +++ b/src/components/LandingPage/LandingInfo.tsx @@ -0,0 +1,65 @@ +import LandingTabSelector from "./LandingTabSelector"; +const info_data = [ + { + title: "Feature preview example one", + description: ` Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, commodo + vel suscipit sit amet, imperdiet sed leo.`, + color: "red", + }, + { + title: "Feature preview example two", + description: ` Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, commodo + vel suscipit sit amet, imperdiet sed leo.`, + color: "indigo", + }, + { + title: "Feature preview example three", + description: ` Mauris mattis lorem a sagittis sagittis. Nulla at vulputate + augue. Sed sit amet mi tortor. Praesent lacus lectus, commodo + vel suscipit sit amet, imperdiet sed leo.`, + color: "red", + }, +]; +export default function LandingInfo() { + return ( +
+
+

Tagline

+

+ One platform for all your dev needs +

+

+ Nunc scelerisque accumsan ante vestibulum consequat. Quisque justo + urna, rhoncus in erat ac, lobortis eleifend nulla. +

+
+ +
+
+
+ {info_data.map((item, idx) => ( +
+
+
+

{item.title}

+

{item.description}

+
+
+ +
+
+ feature preview +
+
+
+ ))} +
+
+ ); +} diff --git a/src/components/LandingPage/LandingPricing.tsx b/src/components/LandingPage/LandingPricing.tsx new file mode 100644 index 0000000..1d9a712 --- /dev/null +++ b/src/components/LandingPage/LandingPricing.tsx @@ -0,0 +1,75 @@ +import { CheckIcon } from "@/assets/svgs/CheckIcon"; +import { pricing_data } from "./pricing-data"; + +export default function LandingPricing() { + return ( + <> +
+
+

Pricing

+

+ Every business has different needs +

+

+ We offer flexible pricing plans tailored to meet the needs and + demand of solopreneurs to large agencies. +

+
+ +
+
+

Monthly

+
+ +
+

Annually

+
+
+

Save 25% on Annual plan 🔥

+
+
+ +
+ {pricing_data.map((item, i) => ( +
+
+
{item.icon}
+

{item.plan}

+
+

${item.price}

+

/month

+
+
+ + +
+ {item.features.map((item, index) => ( +
+
+ +
+

{item}

+
+ ))} +
+
+ ))} +
+
+ + ); +} diff --git a/src/components/LandingPage/LandingTabSelector.tsx b/src/components/LandingPage/LandingTabSelector.tsx new file mode 100644 index 0000000..99a05ec --- /dev/null +++ b/src/components/LandingPage/LandingTabSelector.tsx @@ -0,0 +1,73 @@ +import { useState } from "react"; + +export default function LandingTabSelector() { + const [selected, setSelected] = useState(); + const selectedClassNames = `rounded-[6px] bg-gradient-to-r from-[#262626] to-[#525252] text-gray-100 text-gray-100 px-1 py-1 md:px-3 md:py-2`; + return ( +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ +
+ ); +} diff --git a/src/components/LandingPage/MainHero.tsx b/src/components/LandingPage/MainHero.tsx new file mode 100644 index 0000000..35e0743 --- /dev/null +++ b/src/components/LandingPage/MainHero.tsx @@ -0,0 +1,62 @@ +import LandingTabSelector from "./LandingTabSelector"; + +export default function MainHero() { + return ( + <> +
+
+
+

One stop shop for your dev house

+
+
+

+ AI-driven, one stop shop for your dev house +

+

+ Speed up your process by creating{" "} + wireframes and + + {" "} + working prototypes, code exports + {" "} + and APIs built by AI - + all in one platform +

+
+
+ + +
+
+
+
+ +
+
+ dashboard-wireframe +
+
+
+ + ); +} diff --git a/src/components/LandingPage/QuickAndEasy.tsx b/src/components/LandingPage/QuickAndEasy.tsx new file mode 100644 index 0000000..fde9944 --- /dev/null +++ b/src/components/LandingPage/QuickAndEasy.tsx @@ -0,0 +1,189 @@ +import LandingTabSelector from "./LandingTabSelector"; + +export default function QuickAndEasy() { + return ( +
+
+

Tagline

+

+ One platform for all your dev needs +

+

+ Nunc scelerisque accumsan ante vestibulum consequat. Quisque justo + urna, rhoncus in erat ac, lobortis eleifend nulla. +

+
+ +
+
+ +
+
Wireframes - quick and easy
+
+
+
+ + + + + +
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+ + + +
+

+ Aliquam sed erat lacus. Nam iaculis nulla non elit porttitor, at + finibus ipsum hendrerit. Aliquam iaculis orci quis arcu + condimentum egestas. +

+
+
+
+ + + +
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+ + + + +
+

+ In quis ultricies nibh, in suscipit lectus. Donec nec auctor + sapien. Vivamus porta mauris sed augue pretium, a tristique metus + ultricies. +

+
+
+
+ + + + + + +
+

+ Quisque vulputate pharetra purus, at semper augue posuere at. Duis + placerat ac diam quis malesuada. Donec ac dictum eros, in mollis + libero. Cras odio nisi, consequat bibendum orci ac, ullamcorper + varius mi. +

+
+
+
+ + + +
+

+ Donec sit amet metus elit. Donec sagittis, ligula ac condimentum + cursus, ex ex ultrices lectus, a ornare neque leo et eros. Donec + tempus ligula id enim aliquam dignissim. Mauris iaculis diam non + dapibus pharetra. +

+
+
+
+
+ ); +} diff --git a/src/components/LandingPage/index.ts b/src/components/LandingPage/index.ts new file mode 100644 index 0000000..d6146d8 --- /dev/null +++ b/src/components/LandingPage/index.ts @@ -0,0 +1,14 @@ + + import { lazy } from "react"; + + export const HowItWorks = lazy(() => import("./HowItWorks")); +export const LandingCta = lazy(() => import("./LandingCta")); +export const LandingDetailView = lazy(() => import("./LandingDetailView")); +export const LandingFaq = lazy(() => import("./LandingFaq")); +export const LandingFeature = lazy(() => import("./LandingFeature")); +export const LandingInfo = lazy(() => import("./LandingInfo")); +export const LandingPricing = lazy(() => import("./LandingPricing")); +export const LandingTabSelector = lazy(() => import("./LandingTabSelector")); +export const MainHero = lazy(() => import("./MainHero")); +export const QuickAndEasy = lazy(() => import("./QuickAndEasy")); + \ No newline at end of file diff --git a/src/components/LandingPage/pricing-data.ts b/src/components/LandingPage/pricing-data.ts new file mode 100644 index 0000000..8213755 --- /dev/null +++ b/src/components/LandingPage/pricing-data.ts @@ -0,0 +1,41 @@ +export const pricing_data = [ + { + icon: "🧑‍💻‍", + plan: "solo", + price: "9.99", + features: [ + "1 seat", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + ], + }, + { + icon: "👨🏽‍💻👩🏼💻🧑🏾‍💻", + plan: "Team", + price: "9.99", + features: [ + "Up to 5 seats", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + ], + }, + { + icon: "🚀🚀🚀‍🚀", + plan: "Agency", + price: "499.99", + features: [ + "Up to 15 seats", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + "Feature name one", + ], + }, +]; diff --git a/src/components/LazyLoad/LazyLoad.tsx b/src/components/LazyLoad/LazyLoad.tsx new file mode 100644 index 0000000..f83926e --- /dev/null +++ b/src/components/LazyLoad/LazyLoad.tsx @@ -0,0 +1,53 @@ +import React, { memo, Suspense } from "react"; +import { Skeleton } from "@/components/Skeleton"; +import { MKDLOGO } from "@/assets/images"; + +interface LazyLoadProps { + children: React.ReactNode; + counts?: number[]; + count?: number; + className?: string; + circle?: boolean; + brand?: boolean; +} + +const LazyLoad = ({ + children, + counts = [1], + count = 1, + // className, + circle = false, + brand = false, +}: LazyLoadProps) => { + const childrenArray = React.Children.toArray(children).filter(Boolean); + const className = childrenArray.filter(Boolean)[0]?.props?.className + ? childrenArray[0]?.props?.className + : ""; + // console.log("childrenArray >>", childrenArray); + // console.log("className >>", className); + + return ( + + + + Wireframe v5 +
+ ) : ( + + ) + } + > + {children} + + ); +}; + +export default memo(LazyLoad); diff --git a/src/components/LazyLoad/index.ts b/src/components/LazyLoad/index.ts new file mode 100644 index 0000000..1307afd --- /dev/null +++ b/src/components/LazyLoad/index.ts @@ -0,0 +1,2 @@ +// import { lazy } from "react"; +export { default as LazyLoad } from "./LazyLoad"; diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx new file mode 100644 index 0000000..0bfafa0 --- /dev/null +++ b/src/components/Loader/Loader.tsx @@ -0,0 +1,24 @@ +import { LoadingIndicator } from "@/components/LoadingIndicator"; + +interface LoaderProps { + style?: React.CSSProperties; +} + +const Loader: React.FC = ({ style }) => { + return ( +
+ +
+ ); +}; + +export default Loader; diff --git a/src/components/Loader/index.ts b/src/components/Loader/index.ts new file mode 100644 index 0000000..14ed798 --- /dev/null +++ b/src/components/Loader/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const Loader = lazy(() => import("./Loader")); diff --git a/src/components/LoadingIndicator/LoadingIndicator.tsx b/src/components/LoadingIndicator/LoadingIndicator.tsx new file mode 100644 index 0000000..6ac3202 --- /dev/null +++ b/src/components/LoadingIndicator/LoadingIndicator.tsx @@ -0,0 +1,64 @@ +import React from "react"; + +import { motion } from "framer-motion"; + +export interface LoadingIndicatorProps { + dotsClasses?: string; + size?: number; + style?: React.CSSProperties; +} + +const containerVariant = { + start: { + transition: { staggerChildren: 0.2 } + }, + end: { + transition: { staggerChildren: 0.2 } + } +}; + +const dotsVariants = { + start: { + y: "0%" + }, + end: { + y: "100%" + } +}; + +const loadingTransition = { + duration: 0.4, + yoyo: Infinity, + ease: "easeIn" +}; + +const LoadingIndicator: React.FC = ({ dotsClasses, size, style }) => { + const dotsStyles = `block w-[${size ?? 9}px] h-[${size ?? 9}px] bg-slate-900 rounded-md shrink-0 ${dotsClasses ?? ""}`; + return ( + + + + + + ); +}; + +export default LoadingIndicator; diff --git a/src/components/LoadingIndicator/index.ts b/src/components/LoadingIndicator/index.ts new file mode 100644 index 0000000..00e7283 --- /dev/null +++ b/src/components/LoadingIndicator/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const LoadingIndicator = lazy(() => import("./LoadingIndicator")); + + \ No newline at end of file diff --git a/src/components/MKDForm/MKDForm.tsx b/src/components/MKDForm/MKDForm.tsx new file mode 100644 index 0000000..9590d9e --- /dev/null +++ b/src/components/MKDForm/MKDForm.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +const MKDForm = ({ onSubmit, children, className }) => { + return ( + <> + + {children} + + + ); +}; + +export default MKDForm; diff --git a/src/components/MKDForm/index.ts b/src/components/MKDForm/index.ts new file mode 100644 index 0000000..cdc54ab --- /dev/null +++ b/src/components/MKDForm/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const MKDForm = lazy(() => import("./MKDForm")); + \ No newline at end of file diff --git a/src/components/MkdButton/MkdButton.module.css b/src/components/MkdButton/MkdButton.module.css new file mode 100644 index 0000000..d82e6a2 --- /dev/null +++ b/src/components/MkdButton/MkdButton.module.css @@ -0,0 +1,31 @@ +.button { + position: relative; + border: none; + color: #ffffff; + text-align: center; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + text-decoration: none; + overflow: hidden; + cursor: pointer; +} +.button:after { + content: ""; + background-color: #6752e0; + /* background: #4f46e5; */ + display: block; + position: absolute; + padding-top: 300%; + padding-left: 350%; + margin-left: -20px !important; + margin-top: -120%; + opacity: 0; + transition: all 0.8s; +} + +.button:active:after { + padding: 0; + margin: 0; + opacity: 1; + transition: 0s; +} diff --git a/src/components/MkdButton/MkdButton.tsx b/src/components/MkdButton/MkdButton.tsx new file mode 100644 index 0000000..a079532 --- /dev/null +++ b/src/components/MkdButton/MkdButton.tsx @@ -0,0 +1,52 @@ +import { ReactNode, useState } from "react"; +import classes from "./MkdButton.module.css"; + +interface MkdButtonProps { + onClick?: () => void; + children?: ReactNode; + showPlus?: boolean; + disabled?: boolean; + className?: string; + showChildren?: boolean; + title?: any; + type?: "button" | "submit" | "reset"; +} + +const MkdButton = ({ + onClick, + children = "Add New", + showPlus = true, + className, + title, + disabled = false, + showChildren = true, + type = "button", +}: MkdButtonProps) => { + const [animate, setAnimate] = useState(false); + + const onClickHandle = () => { + if (onClick) { + onClick(); + } + setAnimate(true); + }; + + // const classes = ` after:bg-[#90EE90] after:block after:absolute after:pt-[300%] after:pl-[350%] after:!ml-[-1.25rem] after:mt-[-120%] after:opacity-0 after:transition-all active:after:p-0 active:after:m-0 active:after:opacity-100 `; + + return ( + + ); +}; + +export default MkdButton; diff --git a/src/components/MkdButton/index.ts b/src/components/MkdButton/index.ts new file mode 100644 index 0000000..aa1b0a1 --- /dev/null +++ b/src/components/MkdButton/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdButton = lazy(() => import("./MkdButton")); diff --git a/src/components/MkdCalendar/MkdCalendar.css b/src/components/MkdCalendar/MkdCalendar.css new file mode 100644 index 0000000..1b314a6 --- /dev/null +++ b/src/components/MkdCalendar/MkdCalendar.css @@ -0,0 +1,5 @@ + + .calendar-full-width .fc.fc-media-screen.fc-direction-ltr{ + width:100%; + } + \ No newline at end of file diff --git a/src/components/MkdCalendar/MkdCalendar.tsx b/src/components/MkdCalendar/MkdCalendar.tsx new file mode 100644 index 0000000..f28befe --- /dev/null +++ b/src/components/MkdCalendar/MkdCalendar.tsx @@ -0,0 +1,91 @@ +import { useMemo } from "react"; +import { MkdButton } from "@/components/MkdButton"; +import { LazyLoad } from "@/components/LazyLoad"; +import "react-modern-calendar-datepicker/lib/DatePicker.css"; +import { Calendar } from "react-modern-calendar-datepicker"; + +interface MkdCalendarProps { + selectedDay: any; + setSelectedDay: (date: any) => void; + showDate?: boolean; + showTime?: boolean; + onSave?: () => void; +} + +const MkdCalendar = ({ + selectedDay, + setSelectedDay, + showDate = true, + showTime = true, + onSave, +}: MkdCalendarProps) => { + return ( + <> + +
+ {showDate && } + + + + Save + + +
+ + ); +}; + +export default MkdCalendar; + +const locale = useMemo( + () => ({ + weekDays: [ + { + name: "Sunday", + short: "sun", + isWeekend: true, + }, + { + name: "Monday", + short: "mon", + isWeekend: false, + }, + { + name: "Tuesday", + short: "tue", + isWeekend: false, + }, + { + name: "Wednesday", + short: "wed", + isWeekend: false, + }, + { + name: "Thursday", + short: "thu", + isWeekend: false, + }, + { + name: "Friday", + short: "fri", + isWeekend: false, + }, + { + name: "Saturday", + short: "sat", + isWeekend: true, + }, + ], + }), + [] +); diff --git a/src/components/MkdCalendar/index.js b/src/components/MkdCalendar/index.js new file mode 100644 index 0000000..0793ac4 --- /dev/null +++ b/src/components/MkdCalendar/index.js @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdCalendar = lazy(() => import("./MkdCalendar")); diff --git a/src/components/MkdControlledInput/MkdControlledInput.tsx b/src/components/MkdControlledInput/MkdControlledInput.tsx new file mode 100644 index 0000000..9c5805d --- /dev/null +++ b/src/components/MkdControlledInput/MkdControlledInput.tsx @@ -0,0 +1,73 @@ +import React, { useEffect, useId, useState } from "react"; + +const MkdControlledInput = ({ + onChange, + value, + ref, + id, + className, + type = "text", + placeholder, + label, + children, + component, +}) => { + const generatedId = useId(); + const [focus, setFocus] = useState(false); + const [inputValue, setInputValue] = useState(""); + const [initialLoad, setInitialLoad] = useState(true); + + useEffect(() => { + setInputValue(value); + }, [value]); + + useEffect(() => { + if (initialLoad) { + return setInitialLoad(false); + } + if (onChange) { + onChange({ target: { value: inputValue } }); + } + }, [inputValue]); + + return ( +
+ + +
+ setInputValue(e.target.value)} + placeholder={!focus || inputValue ? "" : placeholder} + onFocus={() => setFocus(true)} + onBlur={() => setFocus(false)} + /> + {children ? ( +
+ {children} +
+ ) : null} +
+ {component ? ( +
{component}
+ ) : null} +
+ ); +}; + +export default MkdControlledInput; diff --git a/src/components/MkdControlledInput/index.ts b/src/components/MkdControlledInput/index.ts new file mode 100644 index 0000000..a136ccc --- /dev/null +++ b/src/components/MkdControlledInput/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdControlledInput = lazy(() => import("./MkdControlledInput")); diff --git a/src/components/MkdDebounceInput/MkdDebounceInput.tsx b/src/components/MkdDebounceInput/MkdDebounceInput.tsx new file mode 100644 index 0000000..1ff31a6 --- /dev/null +++ b/src/components/MkdDebounceInput/MkdDebounceInput.tsx @@ -0,0 +1,116 @@ +import React, { useId, useState } from "react"; +import { StringCaser } from "@/utils/utils"; + +let timeout = null; + +const MkdDebounceInput = ({ + type = "text", + label, + className, + placeholder = "Search", + options = [], + disabled = false, + setValue, + value, + onReady, + timer = 1000, + showIcon = true, +}) => { + const inputId = useId(); + const [inputValue, setInputValue] = useState(""); + + function handleInput(e) { + const inputName = e.target.value; + setValue(inputName); + setInputValue(inputName); + + if (timeout) { + clearTimeout(timeout); + } + + timeout = setTimeout(() => { + // Make the API call here using the `name` state variable + if (inputName.length) { + onReady(inputName); + } + }, timer); // 500 milliseconds = half a second + } + + return ( + <> +
+ + {type === "dropdown" || type === "select" ? ( + + ) : ( +
+ {showIcon && ( +
+ +
+ )} + handleInput(e)} + value={value || inputValue} + className={`block w-full rounded-lg border border-blue-600 bg-white p-4 pl-10 text-sm text-black placeholder-black focus:border-blue-500 focus:ring-blue-500 dark:text-gray-400 dark:placeholder-gray-400 ${className}`} + /> +
+ // handleInput(e)} + // value={value||inputValue} + // className={`focus:shadow-outline w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none ${className}`} + // /> + )} + {/*

+ {errors[name]?.message} +

*/} +
+ + ); +}; + +// + +export default MkdDebounceInput; diff --git a/src/components/MkdDebounceInput/index.ts b/src/components/MkdDebounceInput/index.ts new file mode 100644 index 0000000..6c6a857 --- /dev/null +++ b/src/components/MkdDebounceInput/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from 'react' + + export const MkdDebounceInput = lazy(()=> import("./MkdDebounceInput")) + \ No newline at end of file diff --git a/src/components/MkdFileTable/MkdFileTable.tsx b/src/components/MkdFileTable/MkdFileTable.tsx new file mode 100644 index 0000000..a11a10a --- /dev/null +++ b/src/components/MkdFileTable/MkdFileTable.tsx @@ -0,0 +1,147 @@ +import React, { useRef, useState } from "react"; +import * as XLSX from "xlsx"; +import Papa from "papaparse"; +import { Spinner } from "@/assets/svgs"; + +const acceptType = (fileType) => { + switch (fileType) { + case "excel": + return ".xlsx,.xls"; + case "csv": + return ".csv"; + default: + return ".xlsx,.xls"; + } +}; + +const MkdFileTable = ({ + title = "Table", + className = "", + fileType = "excel", +}) => { + const inputRef = useRef(null); + const [dataLoading, setDataLoading] = useState(false); + const [data, setData] = useState([]); + + const handleExcelFile = (e) => { + try { + setData(() => []); + setDataLoading(true); + const reader = new FileReader(); + reader.readAsBinaryString(e.target.files[0]); + reader.onload = (e) => { + const data = e.target.result; + const workbook = XLSX.read(data, { type: "binary" }); + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + const parsedData = XLSX.utils.sheet_to_json(sheet); + setData(parsedData); + setDataLoading(false); + inputRef.current.value = ""; + }; + } catch (error) { + setDataLoading(false); + inputRef.current.value = ""; + } + }; + + const handleCsvFile = (e) => { + try { + setData(() => []); + setDataLoading(true); + const file = e.target.files[0]; + Papa.parse(file, { + header: true, + complete: (results) => { + setData(results.data); + inputRef.current.value = ""; + setDataLoading(false); + }, + }); + } catch (error) { + inputRef.current.value = ""; + setDataLoading(false); + } + }; + + const handleFileInput = (e) => { + switch (fileType) { + case "excel": + return handleExcelFile(e); + case "csv": + return handleCsvFile(e); + default: + return handleExcelFile(e); + } + }; + + return ( +
+
+
+ + +
+
+
+ {/* */} + {title ? title : "Data Table"} +
+
+ {dataLoading ? ( +
+ +
+ ) : data.length ? ( + + + + {data.length + ? Object.keys(data[0]).map((item, index) => ( + + )) + : null} + + + + {data.map((row, rowIndex) => ( + + {Object.values(row).map((value, valueKey) => ( + + ))} + + ))} + +
+ {item} +
+ {value} +
+ ) : null} +
+
+
+
+ ); +}; + +export default MkdFileTable; diff --git a/src/components/MkdFileTable/index.ts b/src/components/MkdFileTable/index.ts new file mode 100644 index 0000000..df076bd --- /dev/null +++ b/src/components/MkdFileTable/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const MkdFileTable = lazy(() => import("./MkdFileTable")); + \ No newline at end of file diff --git a/src/components/MkdFileUpload/MkdFileUpload.tsx b/src/components/MkdFileUpload/MkdFileUpload.tsx new file mode 100644 index 0000000..489d55b --- /dev/null +++ b/src/components/MkdFileUpload/MkdFileUpload.tsx @@ -0,0 +1,429 @@ +import React, { useId, useRef, useState } from "react"; +import * as XLSX from "xlsx"; +import Papa from "papaparse"; + +const acceptType = (fileType) => { + switch (fileType) { + case "excel": + case "xls": + case "xlsx": + case ".xlsx": + case ".xls": + case ".xlsx,.xls": + case "xlsx,xls": + case ".xls,.xlsx": + case "xls,xlsx": + return ".xlsx,.xls"; + case "csv": + case ".csv": + return ".csv"; + case ".png": + case "png": + return ".png"; + case ".jpg": + case "jpg": + return ".jpg"; + case ".jpeg": + case "jpeg": + return ".jpeg"; + case "image": + case ".png,.jpg,.jpeg": + case ".png,.jpeg,.jpg": + case ".jpg,.png,.jpeg": + case ".jpg,.jpeg,.png": + case ".jpeg,.png,.jpg": + case ".jpeg,.jpg,.png": + return ".png,.jpg,.jpeg"; + case "doc": + case "docx": + case "document": + case ".doc": + case ".docx": + case ".docx,.doc": + case ".doc,.docx": + case "docx,doc": + case "doc,docx": + return ".docx,.doc"; + case "pdf": + case ".pdf": + return ".pdf"; + default: + return "*"; + } +}; +const transformFileType = (fileType) => { + switch (fileType) { + case "excel": + case "xls": + case "xlsx": + case ".xlsx": + case ".xls": + case ".xlsx,.xls": + case "xlsx,xls": + case ".xls,.xlsx": + case "xls,xlsx": + return "an excel"; + case "csv": + case ".csv": + return "a csv"; + case ".png": + case "png": + return "a png"; + case ".jpg": + case "jpg": + return "a jpg"; + case ".jpeg": + case "jpeg": + return "a jpeg"; + case "image": + case ".png,.jpg,.jpeg": + case ".png,.jpeg,.jpg": + case ".jpg,.png,.jpeg": + case ".jpg,.jpeg,.png": + case ".jpeg,.png,.jpg": + case ".jpeg,.jpg,.png": + return "an image"; + case "doc": + case "docx": + case "document": + case ".doc": + case ".docx": + case ".docx,.doc": + case ".doc,.docx": + case "docx,doc": + case "doc,docx": + return "a word document"; + case "pdf": + case ".pdf": + return "a pdf"; + default: + return "any"; + } +}; +const testFileTypeToRender = (fileType) => { + switch (fileType) { + case "excel": + case "xls": + case "xlsx": + case ".xlsx": + case ".xls": + case ".xlsx,.xls": + case "xlsx,xls": + case ".xls,.xlsx": + case "xls,xlsx": + return "excel"; + case "csv": + case ".csv": + return "csv"; + case ".png": + case "png": + return "image"; + case ".jpg": + case "jpg": + return "image"; + case ".jpeg": + case "jpeg": + return "image"; + case "image": + case ".png,.jpg,.jpeg": + case ".png,.jpeg,.jpg": + case ".jpg,.png,.jpeg": + case ".jpg,.jpeg,.png": + case ".jpeg,.png,.jpg": + case ".jpeg,.jpg,.png": + return "image"; + case "doc": + case "docx": + case "document": + case ".doc": + case ".docx": + case ".docx,.doc": + case ".doc,.docx": + case "docx,doc": + case "doc,docx": + return "document"; + case "pdf": + case ".pdf": + return "pdf"; + // default: + // return "any"; + } +}; +const MkdFileUpload = ({ + fileType, + name = "fileData", + multiple = false, + onAddSuccess, +}) => { + const fileInputId = useId(); + const inputRef = useRef(null); + const [dataLoading, setDataLoading] = useState(false); + const [data, setData] = useState([]); + const [dragging, setDragging] = useState(false); + const [uploadedFile, setUploadedFile] = useState(null); + const [fileObj, setFileObj] = React.useState({}); + + const onAddFile = (field, target, multiple = false) => { + let tempFileObj = fileObj; + if (multiple) { + if (tempFileObj[field]) { + tempFileObj[field] = [ + ...tempFileObj[field], + { + file: target.files[0], + tempFile: { + url: URL.createObjectURL(target.files[0]), + name: target.files[0].name, + type: target.files[0].type, + }, + }, + ]; + } else { + tempFileObj[field] = [ + { + file: target.files[0], + tempFile: { + url: URL.createObjectURL(target.files[0]), + name: target.files[0].name, + type: target.files[0].type, + }, + }, + ]; + } + } else { + tempFileObj[field] = { + file: target.files[0], + tempFile: { + url: URL.createObjectURL(target.files[0]), + name: target.files[0].name, + type: target.files[0].type, + }, + }; + } + setFileObj({ ...tempFileObj }); + onAddSuccess({ ...tempFileObj }); + }; + const updateAssets = (field, data, multiple = false) => { + let tempFileObj = fileObj; + if (multiple) { + if (tempFileObj[field]) { + tempFileObj[field] = [ + ...tempFileObj[field], + ...data.map((item) => ({ file: null, tempFile: item })), + ]; + } else { + tempFileObj[field] = [ + ...data.map((item) => ({ file: null, tempFile: item })), + ]; + } + } else { + tempFileObj[field] = { + file: null, + tempURL: data, + }; + } + setFileObj({ ...tempFileObj }); + }; + + const removeItem = (index) => { + let tempFileObj = fileObj; + + if (multiple) { + let tempFiles = tempFileObj[name]; + tempFiles.splice(index, 1); + tempFileObj[name] = [...tempFiles]; + } else { + tempFileObj[name] = null; + } + + setFileObj({ ...tempFileObj }); + }; + + const handleExcelFile = (e, dnd = false) => { + try { + setData(() => []); + setDataLoading(true); + const reader = new FileReader(); + reader.readAsBinaryString(e.target.files[0]); + reader.onload = (e) => { + const data = e.target.result; + const workbook = XLSX.read(data, { type: "binary" }); + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + const parsedData = XLSX.utils.sheet_to_json(sheet); + setData(parsedData); + setDataLoading(false); + inputRef.current.value = ""; + }; + } catch (error) { + setDataLoading(false); + inputRef.current.value = ""; + } + }; + + const handleCsvFile = (e, dnd = false) => { + try { + setData(() => []); + setDataLoading(true); + const file = e.target.files[0]; + Papa.parse(file, { + header: true, + complete: (results) => { + setData(results.data); + inputRef.current.value = ""; + setDataLoading(false); + }, + }); + } catch (error) { + inputRef.current.value = ""; + setDataLoading(false); + } + }; + const handleImageFile = (e, dnd = false) => { + try { + // setData(() => []); + // setDataLoading(true); + // const file = e.target.files[0]; + onAddFile(name, dnd ? e.dataTransfer : { files: e }, multiple); + inputRef.current.value = ""; + // setDataLoading(false); + } catch (error) { + inputRef.current.value = ""; + // setDataLoading(false); + } + }; + const handleDocumentFile = (e, dnd = falsee) => { + try { + setData(() => []); + setDataLoading(true); + const file = e.target.files[0]; + Papa.parse(file, { + header: true, + complete: (results) => { + setData(results.data); + inputRef.current.value = ""; + setDataLoading(false); + }, + }); + } catch (error) { + inputRef.current.value = ""; + setDataLoading(false); + } + }; + const handlePdfFile = (e, dnd = false) => { + try { + setData(() => []); + setDataLoading(true); + const file = e.target.files[0]; + Papa.parse(file, { + header: true, + complete: (results) => { + setData(results.data); + inputRef.current.value = ""; + setDataLoading(false); + }, + }); + } catch (error) { + inputRef.current.value = ""; + setDataLoading(false); + } + }; + + const handleFileInput = (e, dnd = false) => { + onAddFile(name, dnd ? e.dataTransfer : e.target, multiple); + inputRef.current.value = ""; + }; + + const handleDragEnter = (e) => { + e.preventDefault(); + setDragging(true); + }; + + const handleDragOver = (e) => { + e.preventDefault(); + setDragging(true); + }; + + const handleDragLeave = () => { + setDragging(false); + }; + + const handleDrop = (e) => { + e.preventDefault(); + setDragging(false); + + const droppedFiles = e.dataTransfer.files; + if (droppedFiles.length > 0) { + const file = droppedFiles[0]; + setUploadedFile(file); + handleFileInput(e, true); + } + }; + + return ( + <> + +
+
+
+
+ Select/Drag and Drop {transformFileType(fileType)} File. +
+
inputRef.current.click()} + > + Select File +
+
+
+ {multiple && fileObj[name] && fileObj[name].length ? ( + <> + {testFileTypeToRender(fileType) === "image" + ? fileObj[name].map((photo, photoKey) => ( + + )) + : null} + + ) : !multiple && fileObj[name] ? ( + <> + {testFileTypeToRender(fileType) === "image" ? ( +
+ +
+ ) : null} + + ) : null} +
+
+
+ + ); +}; + +export default MkdFileUpload; diff --git a/src/components/MkdFileUpload/index.ts b/src/components/MkdFileUpload/index.ts new file mode 100644 index 0000000..8e23859 --- /dev/null +++ b/src/components/MkdFileUpload/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const MkdFileUpload = lazy(() => import("./MkdFileUpload")); + \ No newline at end of file diff --git a/src/components/MkdGridView/MkdGridCard.tsx b/src/components/MkdGridView/MkdGridCard.tsx new file mode 100644 index 0000000..19969f7 --- /dev/null +++ b/src/components/MkdGridView/MkdGridCard.tsx @@ -0,0 +1,186 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { Spinner } from "@/assets/svgs"; +import { EyeIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/solid"; + +const MkdGridCard = ({ + columns, + row, + actions, + tableRole, + table, + actionId, + setDeleteId, +}) => { + const navigate = useNavigate(); + + return ( + <> +
+ {columns.map((cell, colKey) => { + if ( + cell?.accessor.indexOf("image") > -1 || + cell?.accessor.indexOf("photo") > -1 + ) { + return ( +
+
{cell?.header}:
+
+ +
+
+ ); + } + if ( + cell?.accessor.indexOf("pdf") > -1 || + cell?.accessor.indexOf("doc") > -1 || + cell?.accessor.indexOf("file") > -1 || + cell?.accessor.indexOf("video") > -1 + ) { + return ( +
+
{cell?.header}:
+ +
+ ); + } + if (cell?.accessor === "") { + if ( + [actions?.view, actions?.edit, actions?.delete].includes(true) + ) { + return ( +
+ {actions?.edit && ( + + )} + {actions?.view && ( + + )} + {actions?.approve && ( + + )} + {actions?.delete && ( + + )} +
+ ); + } else { + return null; + } + } + if (cell?.mappingExist) { + return ( +
+
{cell?.header}:
+
+ {cell?.mappings[row[cell?.accessor]]} +
+
+ ); + } + return ( +
+
{cell?.header}:
+
+ {row[cell?.accessor]} +
+
+ ); + })} +
+ + ); +}; + +export default MkdGridCard; diff --git a/src/components/MkdGridView/MkdGridCards.tsx b/src/components/MkdGridView/MkdGridCards.tsx new file mode 100644 index 0000000..37f976b --- /dev/null +++ b/src/components/MkdGridView/MkdGridCards.tsx @@ -0,0 +1,83 @@ +import React from "react"; +import ModalPrompt from "@/components/Modal/ModalPrompt"; +import { capitalize } from "@/utils/utils"; +import { Spinner } from "@/assets/svgs"; +import { colors } from "@/utils/config"; +import MkdGridCard from "./MkdGridCard"; + +const MkdGridCards = ({ + table, + getData, + loading, + columns, + actions, + tableRole, + deleteItem, + deleteLoading, + actionId = "id", + showDeleteModal, + currentTableData, + setShowDeleteModal, +}) => { + const [deleteId, setIdToDelete] = React.useState(null); + + const setDeleteId = async (id) => { + setShowDeleteModal(true); + setIdToDelete(id); + }; + + return ( + <> +
+ {loading ? ( +
+ +
+ ) : ( +
+
+ {currentTableData.map((row, i) => { + return ( + + ); + })} +
+
+ )} +
+ + {showDeleteModal ? ( + { + deleteItem(deleteId); + }} + closeModalFunction={() => { + setIdToDelete(null); + setShowDeleteModal(false); + }} + title={`Delete ${capitalize(table)}`} + message={`You are about to delete ${capitalize( + table + )} ${deleteId}, note that this action is irreversible`} + acceptText={`DELETE`} + rejectText={`CANCEL`} + loading={deleteLoading} + /> + ) : null} + + ); +}; + +export default MkdGridCards; diff --git a/src/components/MkdGridView/MkdGridView.tsx b/src/components/MkdGridView/MkdGridView.tsx new file mode 100644 index 0000000..3f64266 --- /dev/null +++ b/src/components/MkdGridView/MkdGridView.tsx @@ -0,0 +1,305 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { getNonNullValue } from "@/utils/utils"; +import { PaginationBar } from "@/components/PaginationBar"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import { MkdGridCards } from "@/components/MkdGridView"; +import { MkdInput } from "@/components/MkdInput"; + +let sdk = new MkdSDK(); + +const getType = (type) => { + switch (type) { + case "varchar": + return "text"; + case "text": + return "textarea"; + case "mediumtext": + return "textarea"; + case "longtext": + return "textarea"; + case "tinyint": + return "number"; + case "int": + return "number"; + case "bigint": + return "number"; + case "float": + return "number"; + case "double": + return "number"; + case "image": + return "image"; + case "file": + return "file"; + case "date": + return "date"; + case "datetime": + return "datetime"; + default: + return "text"; + } +}; + +const MkdGridView = ({ + columns = [], + actions = { view: true, edit: true, delete: true }, + actionId = "id", + tableRole = "admin", + table = "user", + tableSchema = [], + hasFilter = true, + schemaFields = [], +}) => { + const { dispatch } = React.useContext(AuthContext); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const [showDeleteModal, setShowDeleteModal] = React.useState(false); + const [deleteLoading, setDeleteLoading] = React.useState(false); + const [loading, setLoading] = React.useState(false); + + const schema = yup.object({}); + + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + setLoading(true); + sdk.setTable(table); + const result = await sdk.callRestAPI( + { + payload: { + ...currentTableData, + }, + page: pageNum, + limit: limitNum, + }, + "PAGINATE" + ); + if (result) { + setLoading(false); + } + const { list, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + setLoading(false); + } catch (error) { + setLoading(false); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + setDeleteLoading(true); + sdk.setTable(table); + const result = await sdk.callRestAPI({ id }, "DELETE"); + if (!result?.error) { + setCurrentTableData((list) => + list.filter((x) => Number(x.user_id) !== Number(id)) + ); + setDeleteLoading(false); + setShowDeleteModal(false); + } + } catch (err) { + setDeleteLoading(false); + setShowDeleteModal(false); + tokenExpireError(dispatch, err?.message); + throw new Error(err); + } + }; + + const exportTable = async (id) => { + try { + sdk.setTable(table); + const result = await sdk.exportCSV(); + } catch (err) { + throw new Error(err); + } + }; + + const resetForm = async () => { + reset(); + await getData(0, pageSize); + }; + + const onSubmit = (_data) => { + let filter = {}; + for (const field of schemaFields) { + const [key] = field.split(":"); + filter[key] = getNonNullValue(_data[key]); + } + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( +
+ {hasFilter ? ( +
+

{table} Search

+
+ {tableSchema && tableSchema.length + ? tableSchema + .map((item, key) => { + if (item.is_filter) { + if (Object.keys(item.mapping).length) { + return ( +
+ +
+ ); + } else { + return ( +
+ +
+ ); + } + } + }) + .filter(Boolean) + : null} +
+ + + +
+ ) : null} + +
+
+

{table} Profile

+
+
+
+ +
+ +
+ ); +}; + +export default MkdGridView; diff --git a/src/components/MkdGridView/index.ts b/src/components/MkdGridView/index.ts new file mode 100644 index 0000000..efb60f8 --- /dev/null +++ b/src/components/MkdGridView/index.ts @@ -0,0 +1,7 @@ + + import { lazy } from "react"; + + export const MkdGridCard = lazy(() => import("./MkdGridCard")); +export const MkdGridCards = lazy(() => import("./MkdGridCards")); +export const MkdGridView = lazy(() => import("./MkdGridView")); + \ No newline at end of file diff --git a/src/components/MkdInfiniteScroll/MkdInfiniteScroll.tsx b/src/components/MkdInfiniteScroll/MkdInfiniteScroll.tsx new file mode 100644 index 0000000..4553f40 --- /dev/null +++ b/src/components/MkdInfiniteScroll/MkdInfiniteScroll.tsx @@ -0,0 +1,98 @@ +import React, { useCallback, useEffect, useRef, memo, useState } from "react"; + +const MkdInfiniteScroll = ({ + data, + children, + height, + next, + pageSize, + nextCursor, + className, + setPageSize, + setNextCursor, + setData, +}) => { + const [initialized, setInitialized] = useState(false); + + const scrollRef = useInfiniteScroll(() => { + // logic for loading more data here + if (nextCursor === 0) { + return; + } else { + next(true, nextCursor); + } + }); + + const onUpdatePageSize = useCallback( + (size) => { + setPageSize(size); + setData(() => []); + setNextCursor(() => null); + setInitialized(true); + next(initialized, null); + }, + [initialized, pageSize, data, nextCursor] + ); + + useEffect(() => { + if (!initialized) { + next(initialized, null); + setInitialized(true); + } + }, [initialized]); + + return ( +
+
+ {children} +
+
+ +
+
+ ); +}; + +export default memo(MkdInfiniteScroll); + +function useInfiniteScroll(callback) { + const scrollRef = useRef(null); + + useEffect(() => { + const handleScroll = () => { + const scrollElement = scrollRef.current; + if ( + scrollElement.scrollTop + scrollElement.clientHeight >= + scrollElement.scrollHeight + ) { + callback(); + } + }; + + const scrollElement = scrollRef.current; + scrollElement.addEventListener("scroll", handleScroll); + + return () => { + scrollElement.removeEventListener("scroll", handleScroll); + }; + }, [callback]); + + return scrollRef; +} + diff --git a/src/components/MkdInfiniteScroll/index.ts b/src/components/MkdInfiniteScroll/index.ts new file mode 100644 index 0000000..18f05bd --- /dev/null +++ b/src/components/MkdInfiniteScroll/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdInfiniteScroll = lazy(() => import("./MkdInfiniteScroll")); diff --git a/src/components/MkdInput/MkdInput.tsx b/src/components/MkdInput/MkdInput.tsx new file mode 100644 index 0000000..9effcbf --- /dev/null +++ b/src/components/MkdInput/MkdInput.tsx @@ -0,0 +1,391 @@ +import { useId, useState } from "react"; +import { StringCaser } from "@/utils/utils"; +import Toggle from "react-toggle"; +import { Skeleton as SkeletonLoader } from "@/components/Skeleton"; +import { LazyLoad } from "@/components/LazyLoad"; +import { Modal } from "@/components/Modal"; +import { MkdCalendar } from "@/components/MkdCalendar"; +import { CalendarIcon } from "@/assets/svgs"; + +interface MkdInputProps { + type: string; + page?: string; + cols?: string; + rows?: string; + name: string; + label: string; + errors?: any; + register?: any; + className?: string; + placeholder?: string; + options?: any[]; + mapping?: any; + disabled?: boolean; + value?: any; + checked?: any; + onChange?: any; + loading?: boolean; + required?: boolean; + labelClassName?: string; + customField?: boolean; + showErrorMessage?: boolean; +} + +const MkdInput = ({ + type = "text", + page, + cols = "30", + rows = "50", + name, + label, + errors = null, + register = null, + className, + placeholder, + options = [], + mapping = null, + disabled = false, + value = null, + checked = null, + onChange, + loading = false, + required = false, + labelClassName = "", + customField = false, + showErrorMessage = true, +}: MkdInputProps) => { + const uniqueId = useId(); + + const [selectedDay, setSelectedDay] = useState(null); + const [inputData, setInputData] = useState({ + modal: null as string | null, + showModal: false, + }); + + const onToggleModal = (modal: string | null, toggle: boolean) => { + setInputData((prev) => ({ ...prev, modal, showModal: toggle })); + }; + + return ( + <> +
+ {["radio", "checkbox", "color", "toggle"].includes(type) ? null : ( + <> + {label && ( + + )} + + )} + {loading ? ( + + ) : type === "textarea" ? ( + <> + + + ) : ["radio", "checkbox", "color", "toggle"].includes(type) ? ( +
+ {["toggle"].includes(type) ? ( + + ) : ( + + )} + +
+ ) : type === "dropdown" || type === "select" ? ( + + ) : type === "mapping" ? ( + <> + {mapping ? ( + + ) : ( + `Please Pass the mapping e.g {key:value}` + )} + + ) : ["number", "decimal"].includes(type) ? ( + { + let value = (e.target as HTMLInputElement).value; + + // If the input starts with '.', prepend '0' + if (value.startsWith(".")) { + value = `0${value}`; + } + + // Allow only numbers with up to 2 decimal places + if (!/^\d+(\.\d{0,2})?$/.test(value)) { + value = value.slice(0, -1); // Remove last invalid character + } + + (e.target as HTMLInputElement).value = value; // Update the input value + }} + className={`focus:shadow-outline font-inter h-[3rem] w-full appearance-none rounded-[.625rem] border p-[.625rem] px-3 py-2 leading-tight text-black shadow focus:outline-none focus:ring-0 ${className} ${ + errors && errors?.[name] && errors?.[name]?.message + ? "!border-red-500" + : "border-soft-200" + } ${disabled ? "appearance-none bg-gray-200" : ""}`} + /> + ) : ["custom_date"].includes(type) ? ( +
{ + if (disabled) return; + onToggleModal("custom_date", true); + }} + className="relative cursor-pointer" + > + + {/* p-[.75rem_1rem_.75rem_1rem] */} + +
+ ) : ( + + )} + + {showErrorMessage && errors && errors?.[name] && ( +

+ {StringCaser(errors?.[name]?.message, { + casetype: "capitalize", + separator: " ", + })} +

+ )} +
+ + onToggleModal(null, false)} + classes={{ + modalDialog: + "!px-0 !rounded-[.125rem] h-fit min-h-fit max-h-fit !w-full !max-w-full !min-w-full ", + modalContent: `!z-10 !mt-0 overflow-hidden !pt-0`, + modal: "h-full", + }} + > + {inputData.showModal && ["custom_date"].includes(inputData.modal!) ? ( + + { + onChange({ target: { value: selectedDay } }); + onToggleModal(null, false); + }} + /> + + ) : null} + + + ); +}; + +export default MkdInput; +function determineModalTitle(modal: string) { + const modalSplit = modal.split("_"); + const includesDate = modalSplit.includes("date"); + const includesTime = modalSplit.includes("time"); + + if (includesDate && includesTime) { + return "Pick date & time"; + } + + if (includesDate) { + return "Pick date"; + } + + if (includesTime) { + return "Select Time"; + } + + return StringCaser(modal, { casetype: "capitalize", separator: " " }); +} diff --git a/src/components/MkdInput/index.ts b/src/components/MkdInput/index.ts new file mode 100644 index 0000000..0c2b718 --- /dev/null +++ b/src/components/MkdInput/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const MkdInput = lazy(() => import("./MkdInput")); + \ No newline at end of file diff --git a/src/components/MkdJsonQuiz/AnswerTypes/MultipleChoice.tsx b/src/components/MkdJsonQuiz/AnswerTypes/MultipleChoice.tsx new file mode 100644 index 0000000..2ac132c --- /dev/null +++ b/src/components/MkdJsonQuiz/AnswerTypes/MultipleChoice.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import MkdJsonQuizOptions from "../MkdJsonQuizOptions"; +import { QuestionTypes } from "../MkdJsonQuiz"; + +const MultipleChoice = ({ updateQuestions, currentQuestion }) => { + return ( + <> + {currentQuestion && + currentQuestion?.type === QuestionTypes.multiple_choice ? ( + + ) : null} + + ); +}; + +export default MultipleChoice; diff --git a/src/components/MkdJsonQuiz/AnswerTypes/ShortLongAnswer.tsx b/src/components/MkdJsonQuiz/AnswerTypes/ShortLongAnswer.tsx new file mode 100644 index 0000000..bc95a4e --- /dev/null +++ b/src/components/MkdJsonQuiz/AnswerTypes/ShortLongAnswer.tsx @@ -0,0 +1,62 @@ +import React, { useId, useState } from "react"; +import { QuestionTypes } from "../MkdJsonQuiz"; + +let timeout = null; + +const ShortLongAnswer = ({ updateQuestions, currentQuestion }) => { + const inputId = useId(); + const [inputValue, setInputValue] = useState(""); + + const getValue = () => { + return inputValue || currentQuestion?.answer; + }; + + function handleInput(e) { + const inputValue = e.target.value; + setInputValue(inputValue); + + if (timeout) { + clearTimeout(timeout); + } + + timeout = setTimeout(() => { + const tempCurrentQuestion = { ...currentQuestion }; + tempCurrentQuestion["answer"] = inputValue; + updateQuestions(tempCurrentQuestion); + setInputValue(""); + }, 1000); // 500 milliseconds = half a second + } + + return ( + <> + {currentQuestion && + [QuestionTypes.short_answer, QuestionTypes.long_answer].includes( + currentQuestion?.type + ) ? ( +
+ {currentQuestion?.type === QuestionTypes.short_answer ? ( + handleInput(e)} + value={getValue()} + className="block w-full rounded-lg border border-blue-600 bg-white p-4 pl-3 text-sm text-black placeholder-black focus:border-blue-500 focus:ring-blue-500 dark:text-gray-400 dark:placeholder-gray-400" + /> + ) : ( + +

+ {errors.name?.message} +

+
+ +
+ + +
+ + ) : ( + + )} +
+
+
+
+ ); +}; + +export default BoardCardsPage; diff --git a/src/components/MkdTrello/CardMember.tsx b/src/components/MkdTrello/CardMember.tsx new file mode 100644 index 0000000..c7da471 --- /dev/null +++ b/src/components/MkdTrello/CardMember.tsx @@ -0,0 +1,201 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; +import { useParams } from "react-router"; +import CardMemberCard from "./CardMemberCard"; + +let sdk = new MkdSDK(); + +const CardMember = ({ cardId }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [showForm, setShowForm] = React.useState(false); + const [users, setUsers] = React.useState([]); + const [cardMembers, setCardMembers] = React.useState([]); + + const { workspaceId } = useParams(); + + const getWorkspaceMember = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/workspaces/${workspaceId}/members`, + {}, + "GET" + ); + if (!result.error) { + setUsers(result.list); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const getCardUsers = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members`, + {}, + "GET" + ); + if (!result.error) { + setCardMembers(result.list); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const assigneMember = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members/${id}/attach`, + {}, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "User Added"); + getCardUsers(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + (async function () { + await getWorkspaceMember(); + })(); + (async function () { + await getCardUsers(); + })(); + }, []); + + return ( +
+ {cardMembers.length === 0 ? ( +
setShowForm(true)} + className=" relative mt-4 rounded-sm bg-[#c7c8d4] " + > +

+ add member +

+
+ ) : ( + <> +
+

+ + + + Members +

+
+
    + {cardMembers?.map((item, i) => ( + + ))} +
  • +

    setShowForm(true)} + className=" mr-[1px] flex h-[40px] w-[40px] cursor-pointer items-center justify-center rounded-full bg-[#b1b1c8] text-[20px] font-bold uppercase text-white shadow-[0_0_3px_0_#1111115e] hover:bg-[#9e9ecf] " + > + + + +

    +
  • +
+ + )} + + {showForm && ( +
+
setShowForm(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
+
+
+

Members

+ +
+
+ {users.map((item, i) => ( +
assigneMember(item.id)} + > +

+ {item.first_name ? item.first_name.substring(0, 1) : "N"} + {item.last_name ? item.last_name.substring(0, 1) : "/A"} +

+

+ {" "} + {`${ + item.first_name + ? `${item.first_name} ${ + item.last_name ? item.last_name : "N/A" + }` + : "N/A" + }`} +

+
+ ))} +
+
+
+
+ )} +
+ ); +}; + +export default CardMember; diff --git a/src/components/MkdTrello/CardMemberCard.tsx b/src/components/MkdTrello/CardMemberCard.tsx new file mode 100644 index 0000000..55f0507 --- /dev/null +++ b/src/components/MkdTrello/CardMemberCard.tsx @@ -0,0 +1,99 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +let sdk = new MkdSDK(); + +const CardMemberCard = ({ cardId, item, getCardUsers }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [cardMemberProfilePopup, setCardMemberProfilePopup] = + React.useState(false); + + const removeMember = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members/${item.user_id}/detach`, + {}, + "DELETE" + ); + if (!result.error) { + showToast(globalDispatch, "User Removed"); + getCardUsers(); + setCardMemberProfilePopup(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + return ( + <> +
  • +

    setCardMemberProfilePopup(true)} + className=" mr-[3px] flex h-[40px] w-[40px] cursor-pointer items-center justify-center rounded-full bg-[#DE350B] text-[16px] font-bold uppercase text-white shadow-[0_0_3px_0_#1111115e] hover:bg-[#b22b09] " + > + {item.first_name ? item.first_name.substring(0, 1) : "N"} + {item.last_name ? item.last_name.substring(0, 1) : "/A"} +

    +
  • + {cardMemberProfilePopup && ( +
    +
    setCardMemberProfilePopup(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    +
    +

    + {" "} + {item.first_name + ? `${item.first_name} ${ + item.last_name ? item.last_name : "" + }` + : "N/A"} + {} +

    + +
    + +
    +
      +
    • + Remove from card +
    • +
    +
    +
    +
    +
    + )} + + ); +}; + +export default CardMemberCard; diff --git a/src/components/MkdTrello/Col.tsx b/src/components/MkdTrello/Col.tsx new file mode 100644 index 0000000..5a745b0 --- /dev/null +++ b/src/components/MkdTrello/Col.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +const Col = ({ isOver, children }) => { + const className = isOver ? " bg-red-500 min-h-[100px] " : ""; + + return
    {children}
    ; +}; + +export default Col; diff --git a/src/components/MkdTrello/Comment.tsx b/src/components/MkdTrello/Comment.tsx new file mode 100644 index 0000000..0a6b55a --- /dev/null +++ b/src/components/MkdTrello/Comment.tsx @@ -0,0 +1,218 @@ +import React from "react"; +import moment from "moment"; +import MkdSDK from "@/utils/MkdSDK"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import LinkifyText from "./LinkifyText"; +import CommentReplyBox from "./CommentReplyBox"; + +let sdk = new MkdSDK(); + +const Comment = ({ cardId, comment, deleteComment, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [replyCommentBoxShow, setReplyCommentBoxShow] = React.useState(false); + const textareaRef = React.useRef(null); + const user_id = JSON.parse(localStorage.getItem("user")); + + const onSubmit = async (_data) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments/${comment.id}`, + { + comment: JSON.stringify(commentText.split(`\n`)), + }, + "PUT" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + React.useEffect(() => { + setCommentText(JSON.parse(comment?.comment).join(`\n`)); + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentBoxShow]); + + return ( +
    +
    + {!comment.parent_id && ( +

    + ys +

    + )} +
    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ) : ( +
    +
    + + Yea Sin + {" "} + + {moment(comment.update_at) + .startOf(new Date(), "hour") + .fromNow()} + +
    + + + +
      + {user_id === comment.user_id && ( + <> +
    • + +
    • +

      +
    • + +
    • +

      + + )} + +
    • + +
    • +
    +
    + )} + {replyCommentBoxShow && ( + + )} +
    +
    + ); +}; + +export default Comment; diff --git a/src/components/MkdTrello/CommentForm.tsx b/src/components/MkdTrello/CommentForm.tsx new file mode 100644 index 0000000..3a186bc --- /dev/null +++ b/src/components/MkdTrello/CommentForm.tsx @@ -0,0 +1,158 @@ +import React from "react"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const CommentForm = ({ cardId, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(""); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [attachment, setAttachment] = React.useState(""); + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachmentUrl = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + attachment: attachmentUrl.url ? attachmentUrl.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const attachmentHanle = async (e) => { + setAttachment(e.target.files[0]); + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    +

    + ys +

    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + + +
    • +
    +
    +
    +
    + ) : ( + + )} +
    + ); +}; + +export default CommentForm; diff --git a/src/components/MkdTrello/CommentReplyBox.tsx b/src/components/MkdTrello/CommentReplyBox.tsx new file mode 100644 index 0000000..7f21dcc --- /dev/null +++ b/src/components/MkdTrello/CommentReplyBox.tsx @@ -0,0 +1,137 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +const CommentReplyBox = ({ + replyCommentBoxShow, + setReplyCommentBoxShow, + parentId, + cardId, + getComment, +}) => { + let sdk = new MkdSDK(); + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachment = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + parent_id: parentId, + attachment: attachment.url ? attachment.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setReplyCommentBoxShow(!replyCommentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ); +}; + +export default CommentReplyBox; diff --git a/src/components/MkdTrello/CreateNewRoomModal.tsx b/src/components/MkdTrello/CreateNewRoomModal.tsx new file mode 100644 index 0000000..5a528be --- /dev/null +++ b/src/components/MkdTrello/CreateNewRoomModal.tsx @@ -0,0 +1,87 @@ +import { AuthContext } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +const CreateNewRoomModal = ({ createNewRoom, setCreateRoom }) => { + const [otherUsers, setOtherUsers] = React.useState(); + const [unfilteredUsers, setUnfilteredUsers] = React.useState(); + const [search, setSearch] = React.useState(""); + const { state } = React.useContext(AuthContext); + + let sdk = new MkdSDK(); + const getAllUsers = async () => { + try { + let users = await sdk.getAllUsers(); + + if (!users.error) { + setOtherUsers(users?.list.filter((user) => user.id !== state.user)); + setUnfilteredUsers( + users?.list.filter((user) => user.id !== state.user) + ); + } + } catch (err) { + console.log("Error", err); + } + }; + + const filterList = (value) => { + setSearch(value); + if (value.length > 0) { + setOtherUsers( + [...unfilteredUsers].filter((user) => + `${user.first_name.toLowerCase()} ${user.last_name.toLowerCase()}`.includes( + value.toLowerCase() + ) + ) + ); + } else { + setOtherUsers(unfilteredUsers); + } + }; + + React.useEffect(() => { + (async function () { + await getAllUsers(); + })(); + }, []); + + return ( + <> +
    +
    setCreateRoom(false)} + >
    +
    +
    +
    +
    + filterList(e.target.value)} + /> +
      + {otherUsers && + otherUsers.map((user) => ( +
    • createNewRoom(user)} + className={`w-full cursor-pointer bg-white px-4 py-2 hover:bg-gray-200 user-${user.id}`} + > + {user.first_name} {user.last_name} +
    • + ))} +
    +
    +
    +
    +
    +
    + + ); +}; + +export default CreateNewRoomModal; diff --git a/src/components/MkdTrello/DashboardSidebar/DashboardSidebar.tsx b/src/components/MkdTrello/DashboardSidebar/DashboardSidebar.tsx new file mode 100644 index 0000000..91d6b9f --- /dev/null +++ b/src/components/MkdTrello/DashboardSidebar/DashboardSidebar.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import { WorkspaceSidebar } from "../WorkspaceSidebar/WorkspaceSidebar"; +import DefaultSidebar from "./DefaultSidebar"; +import { GlobalContext } from "@/context/Global"; + +const DashboardSidebar = ({ + list, + setWorkspaces, + activeLeftPanel, + setActiveLeftPanel, + activeWorkspaceId, + setActiveWorkspaceId, +}) => { + const { + state: { path }, + dispatch: globalDispatch, + } = React.useContext(GlobalContext); + const [addWorkspaceOpen, setAddWorkspaceOpen] = React.useState(false); + + function handleSingleViewWorkspaceItemClick(path) { + globalDispatch({ + type: "SETPATH", + payload: { + path, + }, + }); + } + + function handleBackButton() { + setActiveLeftPanel("default"); + globalDispatch({ + type: "SETPATH", + payload: { + path: "home", + }, + }); + } + + const onCloseAddWorkspaceModal = React.useCallback(() => { + setAddWorkspaceOpen(false); + }, [addWorkspaceOpen]); + + function renderSidebar(activeState) { + switch (activeState) { + case "default": + return ( + + ); + case "workspace": + return ( + + ); + case "hidden": + return; + + default: + return ; + } + } + + return renderSidebar(activeLeftPanel); +}; + +export default DashboardSidebar; diff --git a/src/components/MkdTrello/DashboardSidebar/DefaultSidebar.tsx b/src/components/MkdTrello/DashboardSidebar/DefaultSidebar.tsx new file mode 100644 index 0000000..9cc06d2 --- /dev/null +++ b/src/components/MkdTrello/DashboardSidebar/DefaultSidebar.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { AddWorkspaceModal } from "../AddWorkspaceModal"; +import { SidebarWorkspace } from "../SidebarWorkspace"; +import { GlobalContext } from "@/context/Global"; + +const DefaultSidebar = ({ + list, + setWorkspaces, + setActiveLeftPanel, + setActiveWorkspaceId, +}) => { + const { + state: { path }, + dispatch: globalDispatch, + } = React.useContext(GlobalContext); + const [addWorkspaceOpen, setAddWorkspaceOpen] = React.useState(false); + + const onCloseAddWorkspaceModal = React.useCallback(() => { + setAddWorkspaceOpen(false); + }, [addWorkspaceOpen]); + function handleStaticSidebarItemClick(path) { + globalDispatch({ + type: "SETPATH", + payload: { + path, + }, + }); + } + function handleWorkspaceSidebarItemClick(id) { + setActiveLeftPanel("workspace"); + setActiveWorkspaceId(id); + globalDispatch({ + type: "SETPATH", + payload: { + path: `${id}`, + }, + }); + } + return ( + <> +
    +
    + {/* */} +
    +
    handleStaticSidebarItemClick("boards")} + className={`m-0 mb-2 h-[2rem] w-full rounded-md border-none p-[0.375rem_0.5rem_0.375rem] text-left text-[1rem] font-bold text-[#172B4D] outline-none hover:bg-[#091e4214] ${path === "boards" ? "bg-[#E4F0F6]" : "" + }`} + > + Boards +
    +
    handleStaticSidebarItemClick("home")} + to={`/pm/dashboard`} + className={`m-0 mb-2 h-[2rem] w-full rounded-md border-none p-[0.375rem_0.5rem_0.375rem] text-left text-[1rem] font-bold text-[#172B4D] outline-none hover:bg-[#091e4214] ${path === "home" ? "bg-[#E4F0F6]" : "" + }`} + > + Home +
    +
    + {/* */} +
    +
    +
    + Workspaces +
    {" "} + +
    + {/* */} + {list.map((ws) => ( + + ))} + {/* */} +
    +
    +
    + + + + ); +}; + +export default DefaultSidebar; diff --git a/src/components/MkdTrello/DashboardSidebar/index.ts b/src/components/MkdTrello/DashboardSidebar/index.ts new file mode 100644 index 0000000..2e74913 --- /dev/null +++ b/src/components/MkdTrello/DashboardSidebar/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + + export const DashboardSidebar = lazy(() => import("./DashboardSidebar")); +export const DefaultSidebar = lazy(() => import("./DefaultSidebar")); + \ No newline at end of file diff --git a/src/components/MkdTrello/DashboardViewScreen/DashboardViewScreen.tsx b/src/components/MkdTrello/DashboardViewScreen/DashboardViewScreen.tsx new file mode 100644 index 0000000..4596db1 --- /dev/null +++ b/src/components/MkdTrello/DashboardViewScreen/DashboardViewScreen.tsx @@ -0,0 +1,105 @@ +import React from "react"; +import { PmBoardsPage } from "../PmBoardsPage"; +import { PmDashboardPage } from "../PmDashboardPage"; +import PmSingleBoard from "../PmSingleBoard"; +import { PmWorkspaceMembers } from "../PmWorkspaceMembers"; +import { GlobalContext } from "@/context/Global"; +import { PmWorkspaceBoards } from "../PmWorkspaceBoards"; + +const DashboardViewScreen = ({ + children, + workspacesList, + activeWorkspaceId, + setActiveWorkspaceId, + activeLeftPanel, + setActiveLeftPanel, + activeBoardId, + setActiveBoardId, +}) => { + const { + state: { path }, + dispatch: globalDispatch, + } = React.useContext(GlobalContext); + + function handleWorkspaceListCardNavClick(id, path) { + setActiveWorkspaceId(id); + setActiveLeftPanel("workspace"); + globalDispatch({ + type: "SETPATH", + payload: { + path, + }, + }); + } + + function handleWorkspaceBoardClick(boardId) { + setActiveBoardId(boardId); + setActiveLeftPanel("hidden"); + globalDispatch({ + type: "SETPATH", + payload: { + path: "workspaceBoards", + }, + }); + } + + function handleBackButton() { + setActiveLeftPanel("default"); + globalDispatch({ + type: "SETPATH", + payload: { + path: "home", + }, + }); + } + + function renderRightView(activeState) { + switch (activeState) { + case "boards": + return ( + + ); + + case "home": + return ; + + case "workspaceBoards": + if (activeLeftPanel === "hidden") { + return ( + + ); + } else + return ( + + ); + + case "workspaceMembers": + return ; + + default: + return
    ; + } + } + return ( +
    + {children} + {renderRightView(path)} +
    + ); +}; +export default DashboardViewScreen; diff --git a/src/components/MkdTrello/DashboardViewScreen/index.ts b/src/components/MkdTrello/DashboardViewScreen/index.ts new file mode 100644 index 0000000..dd096d2 --- /dev/null +++ b/src/components/MkdTrello/DashboardViewScreen/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const DashboardViewScreen = lazy(() => import("./DashboardViewScreen")); + \ No newline at end of file diff --git a/src/components/MkdTrello/DropWrapper.tsx b/src/components/MkdTrello/DropWrapper.tsx new file mode 100644 index 0000000..b0beb10 --- /dev/null +++ b/src/components/MkdTrello/DropWrapper.tsx @@ -0,0 +1,32 @@ +import React from "react"; +import { useDrop } from "react-dnd"; +import { statuses } from "./data"; +import ITEM_TYPE from "./data/types"; + +const DropWrapper = ({ onDrop, children, status }) => { + const [{ isOver }, drop] = useDrop({ + accept: ITEM_TYPE, + canDrop: (item, monitor) => { + const itemIndex = statuses.findIndex((si) => si.status === item.status); + const statusIndex = statuses.findIndex((si) => si.status === status); + return [itemIndex + 1, itemIndex - 1, itemIndex].includes(statusIndex); + }, + drop: (item, monitor) => { + onDrop(item, monitor, status); + }, + collect: (monitor) => ({ + isOver: monitor.isOver(), + }), + }); + + return ( +
    + {React.cloneElement(children, { isOver })} +
    + ); +}; + +export default DropWrapper; diff --git a/src/components/MkdTrello/InstandEditor.tsx b/src/components/MkdTrello/InstandEditor.tsx new file mode 100644 index 0000000..c27d8dc --- /dev/null +++ b/src/components/MkdTrello/InstandEditor.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; + +const InstandEditor = ({ setShowInstandEditor, item, list, getData }) => { + const schema = yup.object({ + name: yup.string().required("Title is required"), + }); + const { + register, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}/cards/${item.id}`, + { name: _data.name }, + "PUT" + ); + if (!result.error) { + getData(); + setShowInstandEditor(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + setValue("name", item.content); + }, []); + + return ( +
    +
    setShowInstandEditor(false)} + className="fixed left-0 top-0 z-[99999] h-full w-full bg-[#11111169]" + >
    +
    +
    + +

    {errors.name?.message}

    +
    + +
    + + +
    +
    +
    + ); +}; + +export default InstandEditor; diff --git a/src/components/MkdTrello/Item.tsx b/src/components/MkdTrello/Item.tsx new file mode 100644 index 0000000..7197378 --- /dev/null +++ b/src/components/MkdTrello/Item.tsx @@ -0,0 +1,106 @@ +import React, { Fragment, useState, useRef } from "react"; +import { useDrag, useDrop } from "react-dnd"; +import Window from "./Window"; +import ITEM_TYPE from "./data/types"; +import InstandEditor from "./InstandEditor"; + +const Item = ({ item, index, moveItem, list, getData }) => { + const ref = useRef(null); + const [showInstandEditor, setShowInstandEditor] = React.useState(false); + const [show, setShow] = useState(false); + + const [, drop] = useDrop({ + accept: ITEM_TYPE, + hover(item, monitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + + if (dragIndex === hoverIndex) { + return; + } + + const hoveredRect = ref.current.getBoundingClientRect(); + const hoverMiddleY = (hoveredRect.bottom - hoveredRect.top) / 2; + const mousePosition = monitor.getClientOffset(); + const hoverClientY = mousePosition.y - hoveredRect.top; + + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + + moveItem(dragIndex, hoverIndex); + item.index = hoverIndex; + }, + }); + + const [{ isDragging }, drag] = useDrag({ + type: ITEM_TYPE, + item: { ...item, index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + + drag(drop(ref)); + + const onOpen = () => setShow(true); + const onClose = () => setShow(false); + + return ( + +
    +
    + {/*
    */} +

    {item.content}

    +
    + +
    + {show && } + {showInstandEditor && ( + + )} + + ); +}; + +export default Item; diff --git a/src/components/MkdTrello/LIstItems.tsx b/src/components/MkdTrello/LIstItems.tsx new file mode 100644 index 0000000..0095673 --- /dev/null +++ b/src/components/MkdTrello/LIstItems.tsx @@ -0,0 +1,224 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { GlobalContext } from "@/context/Global"; +import { AuthContext } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import ListSetting from "./ListSetting"; +import DropWrapper from "./DropWrapper"; +import Item from "./Item"; +import Col from "./Col"; + +const LIstItems = ({ list, cardItems, getData, statuses, items, setItems }) => { + const [cardFormShow, setCardFormShow] = React.useState(false); + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const schema = yup.object({ + name: yup.string().required("Title is required"), + }); + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onDrop = (item, status) => { + const mapping = statuses.find((si) => si.status === status); + + setItems((prevState) => { + const newItems = prevState + .filter((i) => i.id !== item.id) + .concat({ ...item, status, icon: mapping.icon }); + return [...newItems]; + }); + + updateCardListId(item, status); + }; + + const moveItem = (dragIndex, hoverIndex) => { + const item = items[dragIndex]; + setItems((prevState) => { + const newItems = prevState.filter((i, idx) => idx !== dragIndex); + newItems.splice(hoverIndex, 0, item); + return [...newItems]; + }); + }; + + const updateCardListId = async (item, status) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${status}/cards/${item.id}`, + { list_id: status }, + "PUT" + ); + if (!result.error) { + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}/cards`, + { + name: _data.name, + start_date: new Date().toISOString().split("T")[0], + due_date: new Date().toISOString().split("T")[0], + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + getData(); + reset(); + setCardFormShow(!cardFormShow); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + return ( +
    +
    +

    + {list.title.toUpperCase()}{" "} +

    + + +
    + + + {cardItems.map((i, idx) => ( + + ))} + <> + {!cardFormShow && ( + + )} + + {cardFormShow && ( +
    +
    + +

    + {errors.name?.message} +

    +
    + +
    + + +
    +
    + )} + + +
    +
    + ); +}; + +export default LIstItems; diff --git a/src/components/MkdTrello/LandingWrapper/LandingWrapper.tsx b/src/components/MkdTrello/LandingWrapper/LandingWrapper.tsx new file mode 100644 index 0000000..174198c --- /dev/null +++ b/src/components/MkdTrello/LandingWrapper/LandingWrapper.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { DashboardSidebar } from "../DashboardSidebar"; +import { DashboardViewScreen } from "../DashboardViewScreen"; + +const LandingWrapper = ({ list, children, setWorkspaces }) => { + const [activeLeftPanel, setActiveLeftPanel] = React.useState("default"); + const [activeWorkspaceId, setActiveWorkspaceId] = React.useState(); + const [activeBoardId, setActiveBoardId] = React.useState(); + + return ( + <> +
    +
    + + + + {children} + +
    +
    + + ); +}; +export default LandingWrapper; diff --git a/src/components/MkdTrello/LandingWrapper/index.ts b/src/components/MkdTrello/LandingWrapper/index.ts new file mode 100644 index 0000000..36567f8 --- /dev/null +++ b/src/components/MkdTrello/LandingWrapper/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const LandingWrapper = lazy(() => import("./LandingWrapper")); + \ No newline at end of file diff --git a/src/components/MkdTrello/LinkifyText.tsx b/src/components/MkdTrello/LinkifyText.tsx new file mode 100644 index 0000000..2fc0d91 --- /dev/null +++ b/src/components/MkdTrello/LinkifyText.tsx @@ -0,0 +1,54 @@ +import React from "react"; + +const LinkifyText = ({ comment, attachment }) => { + return ( +
    +
    + {" "} + {attachment && ( + + + + + + )} +
    + {comment + ? JSON.parse(comment).map((com, i) => ( + + {com.match(/\(([^)]+)\)/) ? ( + <> + {com.split("[")[0]} + + {com.match(/(?<=\[).*?(?=\])/g)[0]} + + {com.split(")")[1]} + + ) : ( + com + )} +
    +
    + )) + : "N/A"} +
    + ); +}; + +export default LinkifyText; diff --git a/src/components/MkdTrello/ListSetting.tsx b/src/components/MkdTrello/ListSetting.tsx new file mode 100644 index 0000000..08bd10b --- /dev/null +++ b/src/components/MkdTrello/ListSetting.tsx @@ -0,0 +1,350 @@ +import React from "react"; +import { useParams } from "react-router"; +import AlartMolad from "./AlartMolad"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +const ListSetting = ({ cardFormShow, setCardFormShow, list, getData }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [showModal, setShowModal] = React.useState(false); + const [showMoveListModal, setShowMoveListModal] = React.useState(false); + const [showNameChangeModal, setShowNameChangeModal] = React.useState(false); + const [showDeleteModal, setShowDeleteModal] = React.useState(false); + const [showArchiveModal, setShowArchiveModal] = React.useState(false); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [listName, setListName] = React.useState(list.title); + + const { id } = useParams(); + + async function getLists() { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists?order_by=id&direction=asc`, + {}, + "GET" + ); + + const { list } = result; + setCurrentTableData(list); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + const updateListPosition = async (listId) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists/${list.status}`, + { + position: listId, + }, + "PUT" + ); + if (!result.error) { + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const updateListName = async () => { + let sdk = new MkdSDK(); + if (listName) { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists/${list.status}`, + { + name: listName, + }, + "PUT" + ); + if (!result.error) { + getData(); + setShowNameChangeModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } else { + showToast(globalDispatch, "Enter Name"); + } + }; + + const deleteList = async () => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}`, + {}, + "DELETE" + ); + if (!result.error) { + getData(); + setShowDeleteModal(false); + setShowModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const archiveList = async () => { + let sdk = new MkdSDK(); + if (listName) { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}`, + { + archive: true, + }, + "DELETE" + ); + if (!result.error) { + getData(); + setShowArchiveModal(false); + setShowModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } else { + showToast(globalDispatch, "Enter Name"); + } + }; + + React.useEffect(() => { + (async function () { + await getLists(); + })(); + }, []); + + return ( + <> + + {showModal && ( +
    +
    setShowModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + List actions + +
    +
      +
    • { + setCardFormShow(!cardFormShow); + setShowModal(false); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Add Card... +
    • +
    • { + setShowMoveListModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Move List... +
    • +
    • { + setShowNameChangeModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Change Name +
    • +
    • { + setShowDeleteModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Delete +
    • +
    • { + setShowArchiveModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Archive +
    • +
    +
    +
    + )} + {showMoveListModal && ( +
    +
    setShowMoveListModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + Move + +
    +
    + + +
    +
    +
    + )} + {showNameChangeModal && ( +
    +
    setShowNameChangeModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + Change Name + +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +
    + )} + {showDeleteModal && ( + + )} + {showArchiveModal && ( + + )} + + ); +}; + +export default ListSetting; diff --git a/src/components/MkdTrello/Lists.tsx b/src/components/MkdTrello/Lists.tsx new file mode 100644 index 0000000..4ab5628 --- /dev/null +++ b/src/components/MkdTrello/Lists.tsx @@ -0,0 +1,127 @@ +import React from "react"; +import { useDrag, useDrop } from "react-dnd"; +import { AuthContext } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import LIstItems from "./LIstItems"; + +const style = { + border: "1px dashed gray", + padding: "0.5rem 1rem", + marginBottom: ".5rem", + backgroundColor: "white", + cursor: "move", +}; + +const ItemTypes = { + CARD: "card", +}; +const icons = { 1: "⭕️", 2: "🔆️", 3: "📝", 4: "✅" }; + +const Lists = ({ + list, + getData, + statuses, + items, + setItems, + moveList, + id, + index, +}) => { + const { dispatch } = React.useContext(AuthContext); + const [cardItems, setCardItems] = React.useState([]); + + const ref = React.useRef(null); + + const [{ handlerId }, drop] = useDrop({ + accept: ItemTypes.CARD, + collect(monitor) { + return { + handlerId: monitor.getHandlerId(), + }; + }, + hover(item, monitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + if (dragIndex === hoverIndex) { + return; + } + const hoveredRect = ref.current.getBoundingClientRect(); + const hoverMiddleY = (hoveredRect.bottom - hoveredRect.top) / 2; + const mousePosition = monitor.getClientOffset(); + const hoverClientY = mousePosition.y - hoveredRect.top; + + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + moveList(dragIndex, hoverIndex); + item.index = hoverIndex; + }, + }); + const [{ isDragging }, drag] = useDrag({ + type: ItemTypes.CARD, + item: { id, index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + const opacity = isDragging ? 0 : 1; + drag(drop(ref)); + + const getCardsByList = async () => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list?.status}/cards`, + {}, + "GET" + ); + let cardsList = []; + result.list.map((item) => + cardsList.push({ + id: item.id, + icon: icons[item.list_id], + // status: "open", + status: item.list_id, + title: "Human Interest Form", + content: item.name, + }) + ); + setCardItems(cardsList); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + (async function () { + await getCardsByList(); + })(); + }, [list?.status]); + + return ( +
    + +
    + ); +}; + +export default Lists; diff --git a/src/components/MkdTrello/MkdTrello.tsx b/src/components/MkdTrello/MkdTrello.tsx new file mode 100644 index 0000000..7fa8afd --- /dev/null +++ b/src/components/MkdTrello/MkdTrello.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { LandingWrapper } from "./LandingWrapper"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +const sdk = new MkdSDK(); + +export const MkdTrello = () => { + const [workspaces, setWorkspaces] = React.useState([]); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const getWorkspaces = async () => { + try { + const res = await sdk.getAllWorkspaces(); + setWorkspaces(res.list); + globalDispatch({ + type: "SETWORKSPACES", + payload: { + workspaces: workspaces, + }, + }); + } catch (err) { + console.log("error" + " " + err); + } + }; + + React.useEffect(() => { + getWorkspaces(); + }, []); + + if (!!workspaces.length) { + return ; + } +}; diff --git a/src/components/MkdTrello/PmBoardsPage.tsx b/src/components/MkdTrello/PmBoardsPage.tsx new file mode 100644 index 0000000..763fee9 --- /dev/null +++ b/src/components/MkdTrello/PmBoardsPage.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import WorkspacesListCard from "./WorkspacesListCard"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; + +export const PmBoardsPage = ({ + workspacesList, + handleWorkspaceListCardNavClick, + handleWorkspaceBoardClick, +}) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + // const workspaces = useOutletContext(); + // const list = JSON.parse(workspaces); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "boards", + }, + }); + }, []); + + return ( + <> +
    +

    YOUR WORKSPACES

    + {workspacesList.map((ws, index) => ( + + ))} +
    + + ); +}; diff --git a/src/components/MkdTrello/PmDashboardPage.tsx b/src/components/MkdTrello/PmDashboardPage.tsx new file mode 100644 index 0000000..5b118b5 --- /dev/null +++ b/src/components/MkdTrello/PmDashboardPage.tsx @@ -0,0 +1,30 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import React from "react"; + +export const PmDashboardPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "home", + }, + }); + }, []); + return ( + <> +
    +
    +

    Stay on track and up to date

    +

    + Invite people to boards and cards, leave comments, add due dates, + and we'll show the most important activity here. +

    +
    +
    + + ); +}; diff --git a/src/components/MkdTrello/PmSingleBoard.tsx b/src/components/MkdTrello/PmSingleBoard.tsx new file mode 100644 index 0000000..cb2b2a0 --- /dev/null +++ b/src/components/MkdTrello/PmSingleBoard.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { HTML5Backend } from "react-dnd-html5-backend"; +import { DndProvider } from "react-dnd"; +import BoardCardsPage from "./BoardCardsPage"; +import { AuthContext } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; + +const icons = { 1: "⭕️", 2: "🔆️", 3: "📝", 4: "✅" }; + +const PmSingleBoard = ({ activeBoardId, handleBackButton }) => { + const { dispatch } = React.useContext(AuthContext); + const [currentTableData, setCurrentTableData] = React.useState([]); + + async function getData() { + let sdk = new MkdSDK(); + try { + //Gets card list header info + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${activeBoardId}/lists?order_by=id&direction=asc`, + {}, + "GET" + ); + + const { list } = result; + let lists = []; + list.map((item) => + lists.push({ + status: item.id, + title: item.name, + icon: icons[item.id], + color: "#EB5A46", + position: item.position, + }) + ); + setCurrentTableData(lists); + //remove comment from top line and then comment out result2 and 3 + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + React.useEffect(() => { + (async function () { + await getData(); + })(); + }, []); + + return ( +
    + + + + + + + + +
    + ); +}; + +export default PmSingleBoard; diff --git a/src/components/MkdTrello/PmWorkspaceBoards.tsx b/src/components/MkdTrello/PmWorkspaceBoards.tsx new file mode 100644 index 0000000..82556fa --- /dev/null +++ b/src/components/MkdTrello/PmWorkspaceBoards.tsx @@ -0,0 +1,94 @@ +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; +import { AddBoardsModal } from "./AddBoardsModal"; + +export const PmWorkspaceBoards = ({ + activeWorkspaceId, + handleWorkspaceBoardClick, +}) => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [boards, setBoards] = React.useState([]); + const [addWorkspaceOpen, setAddWorkspaceOpen] = React.useState(false); + const sdk = new MkdSDK(); + + const getBoards = async () => { + try { + const res = await sdk.getUserBoards(activeWorkspaceId); + if (res) { + setBoards(res.list); + } + } catch (err) { + console.log("error" + " " + err); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "workspaceBoards", + }, + }); + (async () => { + await getBoards(); + })(); + }, []); + + const onCloseAddWorkspaceModal = React.useCallback(() => { + setAddWorkspaceOpen(false); + }, [addWorkspaceOpen]); + return ( + <> +
    +
    +

    Boards

    +
    + +
    +
    +
    + {boards.length > 0 + ? boards?.map((board, _index) => ( +
    handleWorkspaceBoardClick(board.id)} + className=" flex h-[100px] cursor-pointer items-center justify-center rounded bg-[#007A52] text-lg font-semibold text-white" + title={board.description} + > + {board.name} +
    + )) + : null} +
    +
    + + + + ); +}; diff --git a/src/components/MkdTrello/PmWorkspaceMembers.tsx b/src/components/MkdTrello/PmWorkspaceMembers.tsx new file mode 100644 index 0000000..be33583 --- /dev/null +++ b/src/components/MkdTrello/PmWorkspaceMembers.tsx @@ -0,0 +1,321 @@ +import React from "react"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +const columns = [ + { + header: "user_id", + accessor: "user_id", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + { + header: "first name", + accessor: "first_name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "last name", + accessor: "last_name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Action", + accessor: "", + }, +]; + +export const PmWorkspaceMembers = ({ activeWorkspaceId }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [addMemberForm, setAddMemberForm] = React.useState(false); + const [users, setUsers] = React.useState([]); + + async function getUsers() { + let sdk = new MkdSDK(); + try { + const result = await sdk.getAllUsers(); + setUsers(result.list.filter((item) => item.role == "user")); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + const assigneMember = async (id) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/workspaces/${activeWorkspaceId}/members/${id}/attach`, + {}, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "User Added"); + getWorkspaceMember(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const getWorkspaceMember = async () => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/workspaces/${activeWorkspaceId}/members`, + {}, + "GET" + ); + if (!result.error) { + setCurrentTableData(result.list); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "workspaceMembers", + }, + }); + (async function () { + await getUsers(); + })(); + (async function () { + await getWorkspaceMember(); + })(); + }, []); + + return ( + <> +
    +
    +
    +

    Member

    +
    + +
    +
    +
    + + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor == "parent_id") { + return ( + + ); + } + if (cell.accessor.indexOf("image") > -1) { + return ( + + ); + } + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
    onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " ▼" + : " ▲" + : ""} + +
    + {row[cell.accessor] > 0 + ? categories.filter( + (cat) => cat.id == row[cell.accessor] + )[0]?.name + : ""} + + + + + + + + {cell.mappings[row[cell.accessor]]} + + {row[cell.accessor] ? row[cell.accessor] : "N/A"} +
    +
    +
    +
    + {addMemberForm && ( +
    +
    setAddMemberForm(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + Add Member + +
    + +
    +
    +
    + {users.map((item, i) => ( +
    assigneMember(item.id)} + > +

    + {item.first_name + ? item.first_name.substring(0, 1) + : "N"} + {item.last_name ? item.last_name.substring(0, 1) : "/A"} +

    +

    + {" "} + {`${ + item.first_name + ? `${item.first_name} ${ + item.last_name ? item.last_name : "N/A" + }` + : "N/A" + }`} +

    +
    + ))} +
    +
    +
    +
    +
    + )} + + ); +}; diff --git a/src/components/MkdTrello/PmWorkspacePage.tsx b/src/components/MkdTrello/PmWorkspacePage.tsx new file mode 100644 index 0000000..1bed76c --- /dev/null +++ b/src/components/MkdTrello/PmWorkspacePage.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { Outlet } from "react-router"; +import MkdSDK from "@/utils/MkdSDK"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import { WorkspaceSidebar } from "./WorkspaceSidebar"; +import { DashboardViewScreen } from "./DashboardViewScreen"; + +export const PmWorkspacePage = ({ activeWorkspaceId }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const sdk = new MkdSDK(); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: activeWorkspaceId, + }, + }); + }, [activeWorkspaceId]); + + return ( + <> +
    +
    +
    + + + + + +
    +
    +
    + + ); +}; diff --git a/src/components/MkdTrello/SidebarWorkspace/SidebarWorkspace.tsx b/src/components/MkdTrello/SidebarWorkspace/SidebarWorkspace.tsx new file mode 100644 index 0000000..dc0b675 --- /dev/null +++ b/src/components/MkdTrello/SidebarWorkspace/SidebarWorkspace.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { GlobalContext } from "@/context/Global"; + +const SidebarWorkspace = ({ ws, handleClick }) => { + const { + state: { path }, + } = React.useContext(GlobalContext); + + return ( + <> +
    handleClick(ws.id)} + className={`my-2 flex h-[2.8125rem] w-full items-center justify-start rounded p-[0.375rem_0.5rem_0.375rem_0] hover:bg-slate-300 ${Number(path) === ws.id ? "bg-slate-300" : "" + }`} + > +
    +
    + {ws?.name[0]} +
    +
    + + {ws?.name} Workspace + +
    + + ); +}; +export default SidebarWorkspace; diff --git a/src/components/MkdTrello/SidebarWorkspace/index.ts b/src/components/MkdTrello/SidebarWorkspace/index.ts new file mode 100644 index 0000000..43dfb1f --- /dev/null +++ b/src/components/MkdTrello/SidebarWorkspace/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const SidebarWorkspace = lazy(() => import("./SidebarWorkspace")); + \ No newline at end of file diff --git a/src/components/MkdTrello/Window.tsx b/src/components/MkdTrello/Window.tsx new file mode 100644 index 0000000..f9b8129 --- /dev/null +++ b/src/components/MkdTrello/Window.tsx @@ -0,0 +1,265 @@ +import React from "react"; +import Modal from "react-modal"; +import AttachmentCard from "./AttachmentCard"; +import CardMember from "./CardMember"; +import Comment from "./Comment"; +import CommentForm from "./CommentForm"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const Window = ({ show, onClose, item }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [currentTableData, setCurrentTableData] = React.useState({}); + const [attachmentsList, setAttachmentsList] = React.useState([]); + const [commentsList, setCommentsList] = React.useState([]); + + async function getData() { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}`, + {}, + "GET" + ); + const result2 = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/attachments?order_by=id&direction=asc`, + {}, + "GET" + ); + setAttachmentsList(result2.list); + const { model } = result; + setCurrentTableData(model); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + async function getComment() { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/comments?order_by=id&direction=desc&limit=20`, + {}, + "GET" + ); + setCommentsList(result.list); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + React.useEffect(() => { + (async function () { + await getData(); + })(); + (async function () { + await getComment(); + })(); + }, []); + + const attachmentHanle = async (e) => { + try { + let formData = new FormData(); + formData.append("file", e.target.files[0]); + const attachment = await sdk.uploadImage(formData); + if (attachment.url) { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/attachments`, + { + name: e.target.files[0].name, + attachment: attachment.url, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + getData(); + } + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const deleteAttachment = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/attachments/${id}`, + {}, + "DELETE" + ); + if (!result.error) { + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const deleteComment = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/comments/${id}`, + {}, + "DELETE" + ); + if (!result.error) { + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + Modal.setAppElement("body"); + + return ( + +
    +

    + {currentTableData.name} +

    + +
    +
    +

    {item.content}

    +

    {/* {item.name} */}

    +
    + + + +
    + {/* Attachment secttion */} +
    + {attachmentsList.length > 0 ? ( +
    +

    + + + + attachments +

    +
    + ) : ( +
    + +

    + add attachment +

    +
    + )} + + {attachmentsList?.map((attach, i) => ( + + ))} + {attachmentsList.length > 0 && ( + + )} +
    + + {/* Comment secttion */} +
    +
    + + + +

    Comments

    +
    + + + + {commentsList.length > 0 && + commentsList?.map((com, i) => ( + + ))} +
    +
    + ); +}; + +export default Window; diff --git a/src/components/MkdTrello/WorkspaceSidebar/WorkspaceSidebar.tsx b/src/components/MkdTrello/WorkspaceSidebar/WorkspaceSidebar.tsx new file mode 100644 index 0000000..c05fb88 --- /dev/null +++ b/src/components/MkdTrello/WorkspaceSidebar/WorkspaceSidebar.tsx @@ -0,0 +1,102 @@ +import React from "react"; +import MkdSDK from "@/utils/MkdSDK"; +import { GlobalContext } from "@/context/Global"; + +const sdk = new MkdSDK(); + +const WorkspaceSidebar = ({ + activeWorkspaceId, + handleSidebarClick, + handleBackButton, +}) => { + const [workspace, setWorkspace] = React.useState({}); + const { + state: { path }, + } = React.useContext(GlobalContext); + + const getSingleWorkspace = async () => { + try { + const res = await sdk.getWorkspace(activeWorkspaceId); + if (res) { + setWorkspace(res.model); + } + } catch (err) { + console.log("error" + " " + err); + } + }; + + React.useEffect(() => { + (async () => { + await getSingleWorkspace(); + })(); + }, []); + + return ( +
    +
    + + + + + +
    +
    +
    + {"D"} +
    +
    + + {workspace.name ? workspace.name : "N/A"} + +
    + +
    +
    handleSidebarClick("workspaceBoards")} + className={`m-0 mb-2 h-[2rem] w-full rounded-md border-none p-[0.375rem_0.5rem_0.375rem] pb-2 text-left text-[1rem] text-[#172B4D] outline-none hover:bg-[#091e4214] ${ + path === "boards" ? "bg-[#E4F0F6]" : "" + }`} + > + Boards +
    +
    handleSidebarClick("workspaceMembers")} + className={`m-0 mb-2 h-[2rem] w-full rounded-md border-none p-[0.375rem_0.5rem_0.375rem] text-left text-[1rem] text-[#172B4D] outline-none hover:bg-[#091e4214] ${ + path === "members" ? "bg-[#E4F0F6]" : "" + }`} + > + Members +
    +
    + Workspace Setting +
    +
    +
    +
    + ); +}; +export default WorkspaceSidebar; diff --git a/src/components/MkdTrello/WorkspaceSidebar/index.ts b/src/components/MkdTrello/WorkspaceSidebar/index.ts new file mode 100644 index 0000000..c6070bd --- /dev/null +++ b/src/components/MkdTrello/WorkspaceSidebar/index.ts @@ -0,0 +1,5 @@ + + import { lazy } from "react"; + + export const WorkspaceSidebar = lazy(() => import("./WorkspaceSidebar")); + \ No newline at end of file diff --git a/src/components/MkdTrello/WorkspacesListCard.tsx b/src/components/MkdTrello/WorkspacesListCard.tsx new file mode 100644 index 0000000..832c2d0 --- /dev/null +++ b/src/components/MkdTrello/WorkspacesListCard.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { AddBoardsModal } from "./AddBoardsModal"; +import MkdSDK from "@/utils/MkdSDK"; + +const WorkspacesListCard = ({ + ws, + handleWorkspaceListCardNavClick, + handleWorkspaceBoardClick, +}) => { + const [addWorkspaceOpen, setAddWorkspaceOpen] = React.useState(false); + const [boards, setBoards] = React.useState([]); + const sdk = new MkdSDK(); + + const getBoards = async () => { + try { + const res = await sdk.getUserBoards(ws?.id); + if (!res.error) { + setBoards(res.list); + } + } catch (err) { + console.log("error" + " " + err); + } + }; + + React.useEffect(() => { + getBoards(); + }, []); + const onCloseAddWorkspaceModal = React.useCallback(() => { + setAddWorkspaceOpen(false); + }, [addWorkspaceOpen]); + return ( + <> +
    +
    +
    +
    + {ws?.name[0]} +
    + + {ws?.name} + +
    + +
    +
    + handleWorkspaceListCardNavClick(ws?.id, "workspaceBoards") + } + className="cursor-pointer rounded-[3px] bg-[#091e420a] p-[6px_12px_6px_6px] text-sm" + > + Boards +
    +
    + handleWorkspaceListCardNavClick(ws?.id, "workspaceMembers") + } + className="cursor-pointer rounded-[3px] bg-[#091e420a] p-[6px_12px_6px_6px] text-sm" + > + Members +
    + + settings + +
    +
    + +
    + {boards.length > 0 + ? boards?.map((board, _index) => { + return ( +
    handleWorkspaceBoardClick(board?.id)} + className=" flex h-[100px] cursor-pointer items-center justify-center rounded bg-[#007A52] text-lg font-semibold text-white" + title={board?.description} + > + {board?.name} +
    + ); + }) + : null} +
    setAddWorkspaceOpen(true)} + className="flex h-[100px] w-[200px] cursor-pointer items-center justify-center bg-[#091e420a]" + > + Create new board +
    +
    +
    + + + ); +}; + +export default WorkspacesListCard; diff --git a/src/components/MkdTrello/data/index.ts b/src/components/MkdTrello/data/index.ts new file mode 100644 index 0000000..2c88afe --- /dev/null +++ b/src/components/MkdTrello/data/index.ts @@ -0,0 +1,50 @@ +const data = [{ + id: 1, + icon: "⭕️", + status: "open", + title: "Human Interest Form", + content: "Fill out human interest distribution form" +}, { + id: 2, + icon: "⭕️", + status: "open", + title: "Purchase present", + content: "Get an anniversary gift" +}, { + id: 3, + icon: "⭕️", + status: "open", + title: "Invest in investments", + content: "Call the bank to talk about investments" +}, { + id: 4, + icon: "⭕️", + status: "open", + title: "Daily reading", + content: "Finish reading Intro to UI/UX" +}]; + +const statuses = [{ + status: "open", + title: "To do", + icon: "⭕️", + color: "#EB5A46" +}, { + status: "in progress", + title: "in progress", + icon: "🔆️", + color: "#00C2E0" +}, { + status: "in review", + title: "in review", + icon: "📝", + color: "#C377E0" +}, { + status: "done", + title: "done", + icon: "✅", + color: "#3981DE" +}]; + + +export { data, statuses }; \ No newline at end of file diff --git a/src/components/MkdTrello/data/types.ts b/src/components/MkdTrello/data/types.ts new file mode 100644 index 0000000..9af16c6 --- /dev/null +++ b/src/components/MkdTrello/data/types.ts @@ -0,0 +1,3 @@ +const ITEM_TYPE = "ITEM"; + +export default ITEM_TYPE; \ No newline at end of file diff --git a/src/components/MkdTrello/index.ts b/src/components/MkdTrello/index.ts new file mode 100644 index 0000000..385724f --- /dev/null +++ b/src/components/MkdTrello/index.ts @@ -0,0 +1,31 @@ + + import { lazy } from "react"; + + export const AlartMolad = lazy(() => import("./AlartMolad")); +export const AttachmentCard = lazy(() => import("./AttachmentCard")); +export const AttachmentViewer = lazy(() => import("./AttachmentViewer")); +export const BoardCardsPage = lazy(() => import("./BoardCardsPage")); +export const CardMember = lazy(() => import("./CardMember")); +export const CardMemberCard = lazy(() => import("./CardMemberCard")); +export const Col = lazy(() => import("./Col")); +export const Comment = lazy(() => import("./Comment")); +export const CommentForm = lazy(() => import("./CommentForm")); +export const CommentReplyBox = lazy(() => import("./CommentReplyBox")); +export const CreateNewRoomModal = lazy(() => import("./CreateNewRoomModal")); +export const DropWrapper = lazy(() => import("./DropWrapper")); +export const InstandEditor = lazy(() => import("./InstandEditor")); +export const Item = lazy(() => import("./Item")); +export const LinkifyText = lazy(() => import("./LinkifyText")); +export const LIstItems = lazy(() => import("./LIstItems")); +export const Lists = lazy(() => import("./Lists")); +export const ListSetting = lazy(() => import("./ListSetting")); +export const MkdTrello = lazy(() => import("./MkdTrello")); +export const PmBoardsPage = lazy(() => import("./PmBoardsPage")); +export const PmDashboardPage = lazy(() => import("./PmDashboardPage")); +export const PmSingleBoard = lazy(() => import("./PmSingleBoard")); +export const PmWorkspaceBoards = lazy(() => import("./PmWorkspaceBoards")); +export const PmWorkspaceMembers = lazy(() => import("./PmWorkspaceMembers")); +export const PmWorkspacePage = lazy(() => import("./PmWorkspacePage")); +export const Window = lazy(() => import("./Window")); +export const WorkspacesListCard = lazy(() => import("./WorkspacesListCard")); + \ No newline at end of file diff --git a/src/components/MkdTrelloColumns/AlartMolad.tsx b/src/components/MkdTrelloColumns/AlartMolad.tsx new file mode 100644 index 0000000..f01dba5 --- /dev/null +++ b/src/components/MkdTrelloColumns/AlartMolad.tsx @@ -0,0 +1,35 @@ +import React from "react"; + +const AlartMolad = ({ onClose, onClick, text }) => { + return ( +
    +
    onClose(false)} + className=" absolute top-0 left-0 w-full h-full bg-[#0000004f] " + /> +
    +
    +
    +
    {text}
    +
    + + +
    +
    +
    +
    +
    + ); +}; + +export default AlartMolad; diff --git a/src/components/MkdTrelloColumns/AttachmentCard.tsx b/src/components/MkdTrelloColumns/AttachmentCard.tsx new file mode 100644 index 0000000..a88c716 --- /dev/null +++ b/src/components/MkdTrelloColumns/AttachmentCard.tsx @@ -0,0 +1,87 @@ +import moment from "moment"; +import React from "react"; +import AttachmentViewer from "./AttachmentViewer"; + +const mimetype = { + gif: "image/gif", + jpeg: "image/jpeg", + png: "image/png", + webp: "image/webp", + pdf: "application/pdf", +}; + +const AttachmentCard = ({ attach, deleteAttachment }) => { + const [showAttachment, setShowAttachment] = React.useState(false); + + const attachmentObject = { + uploader: { + username: "USER_NAME", + userImage: attach.attachment, + }, + name: attach.name, + link: attach.attachment, + createdAt: attach.create_at, + // mimetype: mimetype[attach.name.slipt(".")[1]], + mimetype: "image/png", + }; + + + return ( + <> +
    + {attach?.name?.split(".")[1] == "pdf" ? ( + + PDF + + ) : ( + + )} + +
    +
    +

    setShowAttachment(true)} + className=" cursor-pointer inline-block hover:underline " + > + {attach.name} +

    +
    +
    + + Added{" "} + + {moment(attach.update_at).startOf(new Date(), "hour").fromNow()} + + +
    + +

    + +

    +
    +
    + {showAttachment ? ( + { + /* Do something (OPTIONAL) */ + }} + /> + ) : null} + + ); +}; + +export default AttachmentCard; diff --git a/src/components/MkdTrelloColumns/AttachmentViewer.tsx b/src/components/MkdTrelloColumns/AttachmentViewer.tsx new file mode 100644 index 0000000..2408bf5 --- /dev/null +++ b/src/components/MkdTrelloColumns/AttachmentViewer.tsx @@ -0,0 +1,78 @@ +import React from "react"; + +const AttachmentViewer = ({ + attachment, + showAttachment, + setShowAttachment, +}) => { + return ( +
    +
    setShowAttachment(false)} + className=" absolute top-0 left-0 w-full h-full bg-[#0000004f] " + > + + + + + + +
    + {/* {attachment.name} */} + + {attachment?.name?.split(".")[1] == "pdf" ? ( + + ) : ( + {attachment.name} + )} +
    +
    +
    + ); +}; + +export default AttachmentViewer; diff --git a/src/components/MkdTrelloColumns/BoardCardsPage.tsx b/src/components/MkdTrelloColumns/BoardCardsPage.tsx new file mode 100644 index 0000000..915a1ef --- /dev/null +++ b/src/components/MkdTrelloColumns/BoardCardsPage.tsx @@ -0,0 +1,192 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import update from "react-addons-update"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import Lists from "./Lists"; +import MkdSDK from "@/utils/MkdSDK"; + +const BoardCardsPage = ({ currentTableData, setCurrentTableData, getData }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [items, setItems] = React.useState([]); + const [showItemsForm, setShowItemsForm] = React.useState(false); + + const schema = yup.object({ + name: yup.string().required("Title is required"), + }); + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${0}/lists`, + { + name: _data.name, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + setCurrentTableData(() => []); + getData(); + reset(); + setShowItemsForm(!showItemsForm); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + const moveList = React.useCallback((dragIndex, hoverIndex) => { + setCurrentTableData((prevCards) => + update(prevCards, { + $splice: [ + [dragIndex, 1], + [hoverIndex, 0, prevCards[dragIndex]], + ], + }) + ); + }, []); + + return ( +
    + {currentTableData?.length > 0 && + currentTableData?.map((list, i) => ( + + ))} +
    +
    +
    + {showItemsForm ? ( +
    +
    + +

    + {errors.name?.message} +

    +
    + +
    + + +
    +
    + ) : ( + + )} +
    +
    +
    +
    + ); +}; + +export default BoardCardsPage; diff --git a/src/components/MkdTrelloColumns/CardMember.tsx b/src/components/MkdTrelloColumns/CardMember.tsx new file mode 100644 index 0000000..544c64b --- /dev/null +++ b/src/components/MkdTrelloColumns/CardMember.tsx @@ -0,0 +1,202 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; +import { useParams } from "react-router"; +import CardMemberCard from "./CardMemberCard"; + +let sdk = new MkdSDK(); + +const CardMember = ({ cardId }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [showForm, setShowForm] = React.useState(false); + const [users, setUsers] = React.useState([]); + const [cardMembers, setCardMembers] = React.useState([]); + + const { workspaceId } = useParams(); + + const getWorkspaceMember = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/workspaces/${workspaceId}/members`, + {}, + "GET" + ); + if (!result.error) { + setUsers(result.list); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const getCardUsers = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members`, + {}, + "GET" + ); + + if (!result.error) { + setCardMembers(result.list); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const assigneMember = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members/${id}/attach`, + {}, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "User Added"); + getCardUsers(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + (async function () { + await getWorkspaceMember(); + })(); + (async function () { + await getCardUsers(); + })(); + }, []); + + return ( +
    + {cardMembers.length === 0 ? ( +
    setShowForm(true)} + className=" relative mt-4 rounded-sm bg-[#c7c8d4] " + > +

    + add member +

    +
    + ) : ( + <> +
    +

    + + + + Members +

    +
    +
      + {cardMembers?.map((item, i) => ( + + ))} +
    • +

      setShowForm(true)} + className=" mr-[1px] flex h-[40px] w-[40px] cursor-pointer items-center justify-center rounded-full bg-[#b1b1c8] text-[20px] font-bold uppercase text-white shadow-[0_0_3px_0_#1111115e] hover:bg-[#9e9ecf] " + > + + + +

      +
    • +
    + + )} + + {showForm && ( +
    +
    setShowForm(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    +
    +

    Members

    + +
    +
    + {users.map((item, i) => ( +
    assigneMember(item.id)} + > +

    + {item.first_name ? item.first_name.substring(0, 1) : "N"} + {item.last_name ? item.last_name.substring(0, 1) : "/A"} +

    +

    + {" "} + {`${ + item.first_name + ? `${item.first_name} ${ + item.last_name ? item.last_name : "N/A" + }` + : "N/A" + }`} +

    +
    + ))} +
    +
    +
    +
    + )} +
    + ); +}; + +export default CardMember; diff --git a/src/components/MkdTrelloColumns/CardMemberCard.tsx b/src/components/MkdTrelloColumns/CardMemberCard.tsx new file mode 100644 index 0000000..55f0507 --- /dev/null +++ b/src/components/MkdTrelloColumns/CardMemberCard.tsx @@ -0,0 +1,99 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +let sdk = new MkdSDK(); + +const CardMemberCard = ({ cardId, item, getCardUsers }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [cardMemberProfilePopup, setCardMemberProfilePopup] = + React.useState(false); + + const removeMember = async () => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/members/${item.user_id}/detach`, + {}, + "DELETE" + ); + if (!result.error) { + showToast(globalDispatch, "User Removed"); + getCardUsers(); + setCardMemberProfilePopup(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + return ( + <> +
  • +

    setCardMemberProfilePopup(true)} + className=" mr-[3px] flex h-[40px] w-[40px] cursor-pointer items-center justify-center rounded-full bg-[#DE350B] text-[16px] font-bold uppercase text-white shadow-[0_0_3px_0_#1111115e] hover:bg-[#b22b09] " + > + {item.first_name ? item.first_name.substring(0, 1) : "N"} + {item.last_name ? item.last_name.substring(0, 1) : "/A"} +

    +
  • + {cardMemberProfilePopup && ( +
    +
    setCardMemberProfilePopup(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    +
    +

    + {" "} + {item.first_name + ? `${item.first_name} ${ + item.last_name ? item.last_name : "" + }` + : "N/A"} + {} +

    + +
    + +
    +
      +
    • + Remove from card +
    • +
    +
    +
    +
    +
    + )} + + ); +}; + +export default CardMemberCard; diff --git a/src/components/MkdTrelloColumns/Col.tsx b/src/components/MkdTrelloColumns/Col.tsx new file mode 100644 index 0000000..687f177 --- /dev/null +++ b/src/components/MkdTrelloColumns/Col.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +const Col = ({ isOver, children }) => { + const className = isOver + ? "bg-[#f5eaea] min-h-[6.25rem] rounded-[.3125rem]" + : ""; + + return ( +
    + {children} +
    + ); +}; + +export default Col; diff --git a/src/components/MkdTrelloColumns/Comment copy.tsx b/src/components/MkdTrelloColumns/Comment copy.tsx new file mode 100644 index 0000000..e71ca7b --- /dev/null +++ b/src/components/MkdTrelloColumns/Comment copy.tsx @@ -0,0 +1,217 @@ +import React from "react"; +import moment from "moment"; +import MkdSDK from "@/utils/MkdSDK"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import LinkifyText from "./LinkifyText"; +import CommentReplyBox from "./CommentReplyBox"; + +let sdk = new MkdSDK(); + +const Comment = ({ cardId, comment, deleteComment, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [replyCommentBoxShow, setReplyCommentBoxShow] = React.useState(false); + const textareaRef = React.useRef(null); + const user_id = JSON.parse(localStorage.getItem("user")); + + const onSubmit = async (_data) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments/${comment.id}`, + { + comment: JSON.stringify(commentText.split(`\n`)), + }, + "PUT" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + React.useEffect(() => { + setCommentText(JSON.parse(comment?.comment).join(`\n`)); + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentBoxShow]); + + return ( +
    +
    + {!comment.parent_id && ( +

    + ys +

    + )} +
    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ) : ( +
    +
    + + Yea Sin + {" "} + + {moment(comment.update_at) + .startOf(new Date(), "hour") + .fromNow()} + +
    + + +
      + {user_id === comment.user_id && ( + <> +
    • + +
    • +

      +
    • + +
    • +

      + + )} + +
    • + +
    • +
    +
    + )} + {replyCommentBoxShow && ( + + )} +
    +
    + ); +}; + +export default Comment; diff --git a/src/components/MkdTrelloColumns/Comment.tsx b/src/components/MkdTrelloColumns/Comment.tsx new file mode 100644 index 0000000..932d8c6 --- /dev/null +++ b/src/components/MkdTrelloColumns/Comment.tsx @@ -0,0 +1,219 @@ +import React from "react"; +import moment from "moment"; +import MkdSDK from "@/utils/MkdSDK"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import LinkifyText from "./LinkifyText"; +import CommentReplyBox from "./CommentReplyBox"; + +let sdk = new MkdSDK(); + +const Comment = ({ cardId, comment, deleteComment, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [replyCommentBoxShow, setReplyCommentBoxShow] = React.useState(false); + const textareaRef = React.useRef(null); + const user_id = JSON.parse(localStorage.getItem("user")); + + const onSubmit = async (_data) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments/${comment.id}`, + { + comment: JSON.stringify(commentText.split(`\n`)), + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + React.useEffect(() => { + setCommentText(JSON.parse(comment?.comment).join(`\n`)); + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentBoxShow]); + + return ( +
    +
    + {!comment.parent_id && ( +

    + ys +

    + )} +
    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ) : ( +
    +
    + + Yea Sin + {" "} + + {moment(comment.update_at) + .startOf(new Date(), "hour") + .fromNow()} + +
    + + + +
      + {user_id === comment.user_id && ( + <> +
    • + +
    • +

      +
    • + +
    • +

      + + )} + +
    • + +
    • +
    +
    + )} + {replyCommentBoxShow && ( + + )} +
    +
    + ); +}; + +export default Comment; diff --git a/src/components/MkdTrelloColumns/CommentForm copy.tsx b/src/components/MkdTrelloColumns/CommentForm copy.tsx new file mode 100644 index 0000000..65fe147 --- /dev/null +++ b/src/components/MkdTrelloColumns/CommentForm copy.tsx @@ -0,0 +1,160 @@ +import React from "react"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const CommentForm = ({ cardId, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(""); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [attachment, setAttachment] = React.useState(""); + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachmentUrl = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + attachment: attachmentUrl.url ? attachmentUrl.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const attachmentHanle = async (e) => { + setAttachment(e.target.files[0]); + + + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    +

    + ys +

    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + + +
    • +
    +
    +
    +
    + ) : ( + + )} +
    + ); +}; + +export default CommentForm; diff --git a/src/components/MkdTrelloColumns/CommentForm.tsx b/src/components/MkdTrelloColumns/CommentForm.tsx new file mode 100644 index 0000000..3a186bc --- /dev/null +++ b/src/components/MkdTrelloColumns/CommentForm.tsx @@ -0,0 +1,158 @@ +import React from "react"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const CommentForm = ({ cardId, getComment }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(""); + const [commentBoxShow, setCommentBoxShow] = React.useState(false); + const [attachment, setAttachment] = React.useState(""); + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachmentUrl = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + attachment: attachmentUrl.url ? attachmentUrl.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setCommentBoxShow(!commentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const attachmentHanle = async (e) => { + setAttachment(e.target.files[0]); + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    +

    + ys +

    +
    + {commentBoxShow ? ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + + +
    • +
    +
    +
    +
    + ) : ( + + )} +
    + ); +}; + +export default CommentForm; diff --git a/src/components/MkdTrelloColumns/CommentReplyBox copy.tsx b/src/components/MkdTrelloColumns/CommentReplyBox copy.tsx new file mode 100644 index 0000000..c531a67 --- /dev/null +++ b/src/components/MkdTrelloColumns/CommentReplyBox copy.tsx @@ -0,0 +1,138 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +const CommentReplyBox = ({ + replyCommentBoxShow, + setReplyCommentBoxShow, + parentId, + cardId, + getComment, +}) => { + let sdk = new MkdSDK(); + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachment = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + parent_id: parentId, + attachment: attachment.url ? attachment.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setReplyCommentBoxShow(!replyCommentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ); +}; + +export default CommentReplyBox; diff --git a/src/components/MkdTrelloColumns/CommentReplyBox.tsx b/src/components/MkdTrelloColumns/CommentReplyBox.tsx new file mode 100644 index 0000000..c531a67 --- /dev/null +++ b/src/components/MkdTrelloColumns/CommentReplyBox.tsx @@ -0,0 +1,138 @@ +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +const CommentReplyBox = ({ + replyCommentBoxShow, + setReplyCommentBoxShow, + parentId, + cardId, + getComment, +}) => { + let sdk = new MkdSDK(); + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [commentText, setCommentText] = React.useState(); + + const textareaRef = React.useRef(null); + + const onSubmit = async (_data) => { + try { + let formData = new FormData(); + formData.append("file", attachment); + const attachment = await sdk.uploadImage(formData); + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${cardId}/comments`, + { + comment: JSON.stringify(commentText.split(`\n`)), + parent_id: parentId, + attachment: attachment.url ? attachment.url : "", + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Comment is Added"); + setCommentText(""); + setReplyCommentBoxShow(!replyCommentBoxShow); + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "0px"; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + "px"; + } + }, [commentText]); + + return ( +
    +
    + + +
    +
    + {commentText ? ( + + ) : ( + + )} + +
    +
      +
    • + + + +
    • +
    +
    +
    +
    + ); +}; + +export default CommentReplyBox; diff --git a/src/components/MkdTrelloColumns/CreateNewRoomModal.tsx b/src/components/MkdTrelloColumns/CreateNewRoomModal.tsx new file mode 100644 index 0000000..c072991 --- /dev/null +++ b/src/components/MkdTrelloColumns/CreateNewRoomModal.tsx @@ -0,0 +1,85 @@ +import { AuthContext } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; + +const CreateNewRoomModal = ({ createNewRoom, setCreateRoom }) => { + const [otherUsers, setOtherUsers] = React.useState(); + const [unfilteredUsers, setUnfilteredUsers] = React.useState(); + const [search, setSearch] = React.useState(""); + const { state } = React.useContext(AuthContext); + + let sdk = new MkdSDK(); + const getAllUsers = async () => { + try { + let users = await sdk.getAllUsers(); + + if (!users.error) { + setOtherUsers(users?.list.filter((user) => user.id !== state.user)); + setUnfilteredUsers( + users?.list.filter((user) => user.id !== state.user) + ); + } + } catch (err) { + console.log("Error", err); + } + }; + + const filterList = (value) => { + setSearch(value); + if (value.length > 0) { + setOtherUsers( + [...unfilteredUsers].filter((user) => + `${user.first_name.toLowerCase()} ${user.last_name.toLowerCase()}`.includes( + value.toLowerCase() + ) + ) + ); + } else { + setOtherUsers(unfilteredUsers); + } + }; + + React.useEffect(() => { + (async function () { + await getAllUsers(); + })(); + }, []); + + return ( +
    +
    setCreateRoom(false)} + >
    +
    +
    +
    +
    + filterList(e.target.value)} + /> +
      + {otherUsers && + otherUsers.map((user) => ( +
    • createNewRoom(user)} + className={`w-full cursor-pointer bg-white px-4 py-2 hover:bg-gray-200 user-${user.id}`} + > + {user.first_name} {user.last_name} +
    • + ))} +
    +
    +
    +
    +
    +
    + ); +}; + +export default CreateNewRoomModal; diff --git a/src/components/MkdTrelloColumns/DropWrapper.tsx b/src/components/MkdTrelloColumns/DropWrapper.tsx new file mode 100644 index 0000000..22b9c5f --- /dev/null +++ b/src/components/MkdTrelloColumns/DropWrapper.tsx @@ -0,0 +1,32 @@ +import React from "react"; +import { useDrop } from "react-dnd"; +import { statuses } from "./data"; +import ITEM_TYPE from "./data/types"; + +const DropWrapper = ({ onDrop, children, status }) => { + const [{ isOver }, drop] = useDrop({ + accept: ITEM_TYPE, + canDrop: (item, monitor) => { + const itemIndex = statuses.findIndex((si) => si.status === item.status); + const statusIndex = statuses.findIndex((si) => si.status === status); + return [itemIndex + 1, itemIndex - 1, itemIndex].includes(statusIndex); + }, + drop: (item, monitor) => { + onDrop(item, monitor, status); + }, + collect: (monitor) => ({ + isOver: monitor.isOver(), + }), + }); + + return ( +
    + {React.cloneElement(children, { isOver })} +
    + ); +}; + +export default DropWrapper; diff --git a/src/components/MkdTrelloColumns/InstandEditor.tsx b/src/components/MkdTrelloColumns/InstandEditor.tsx new file mode 100644 index 0000000..39c9767 --- /dev/null +++ b/src/components/MkdTrelloColumns/InstandEditor.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; + +const InstandEditor = ({ setShowInstandEditor, item, list, getData }) => { + const schema = yup.object({ + name: yup.string().required("Title is required"), + }); + const { + register, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}/cards/${item.id}`, + { name: _data.name }, + "PUT" + ); + if (!result.error) { + getData(); + setShowInstandEditor(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + setValue("name", item.content); + }, []); + + return ( +
    +
    setShowInstandEditor(false)} + className="fixed left-0 top-0 z-[99999] h-full w-full bg-[#11111169]" + >
    +
    +
    + +

    {errors.name?.message}

    +
    + +
    + + +
    +
    +
    + ); +}; + +export default InstandEditor; diff --git a/src/components/MkdTrelloColumns/Item.tsx b/src/components/MkdTrelloColumns/Item.tsx new file mode 100644 index 0000000..735b1c7 --- /dev/null +++ b/src/components/MkdTrelloColumns/Item.tsx @@ -0,0 +1,106 @@ +import React, { Fragment, useState, useRef } from "react"; +import { useDrag, useDrop } from "react-dnd"; +import Window from "./Window"; +import ITEM_TYPE from "./data/types"; +import InstandEditor from "./InstandEditor"; + +const Item = ({ item, index, moveItem, list, getData }) => { + const ref = useRef(null); + const [showInstandEditor, setShowInstandEditor] = React.useState(false); + const [show, setShow] = useState(false); + + const [, drop] = useDrop({ + accept: ITEM_TYPE, + hover(item, monitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + + if (dragIndex === hoverIndex) { + return; + } + + const hoveredRect = ref.current.getBoundingClientRect(); + const hoverMiddleY = (hoveredRect.bottom - hoveredRect.top) / 2; + const mousePosition = monitor.getClientOffset(); + const hoverClientY = mousePosition.y - hoveredRect.top; + + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + + moveItem(dragIndex, hoverIndex); + item.index = hoverIndex; + }, + }); + + const [{ isDragging }, drag] = useDrag({ + type: ITEM_TYPE, + item: { type: ITEM_TYPE, ...item, index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + + drag(drop(ref)); + + const onOpen = () => setShow(true); + const onClose = () => setShow(false); + + return ( + +
    +
    + {/*
    */} +

    {item.content}

    +
    + +
    + {show && } + {showInstandEditor && ( + + )} + + ); +}; + +export default Item; diff --git a/src/components/MkdTrelloColumns/LIstItems.tsx b/src/components/MkdTrelloColumns/LIstItems.tsx new file mode 100644 index 0000000..cb0cdad --- /dev/null +++ b/src/components/MkdTrelloColumns/LIstItems.tsx @@ -0,0 +1,237 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import ListSetting from "./ListSetting"; +import DropWrapper from "./DropWrapper"; +import Item from "./Item"; +import Col from "./Col"; + +const LIstItems = ({ + list, + cardItems, + getData, + statuses, + items, + setItems, + setCurrentTableData, +}) => { + const [cardFormShow, setCardFormShow] = React.useState(false); + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const schema = yup.object({ + name: yup.string().required("Title is required"), + }); + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onDrop = (item, status) => { + const mapping = statuses.find((si) => si.status === status); + + setItems((prevState) => { + const newItems = prevState + .filter((i) => i?.id !== item?.id) + .concat({ ...item, status, icon: mapping?.icon }); + return [...newItems]; + }); + + updateCardListId(item, status); + }; + + const moveItem = (dragIndex, hoverIndex) => { + const item = items[dragIndex]; + setItems((prevState) => { + const newItems = prevState.filter((i, idx) => idx !== dragIndex); + newItems.splice(hoverIndex, 0, item); + return [...newItems]; + }); + }; + + const updateCardListId = async (item, status) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${status}/cards/${item.id}`, + { list_id: status }, + "PUT" + ); + if (!result.error) { + setCurrentTableData(() => []); + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}/cards`, + { + name: _data.name, + start_date: new Date().toISOString().split("T")[0], + due_date: new Date().toISOString().split("T")[0], + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + setCurrentTableData(() => []); + getData(); + reset(); + setCardFormShow(!cardFormShow); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + return ( +
    +
    +

    + {list.title.toUpperCase()}{" "} +

    + + +
    + + + {cardItems.map((i, idx) => ( + + ))} + + { + <> + {!cardFormShow && ( + + )} + + {cardFormShow && ( +
    +
    + +

    + {errors.name?.message} +

    +
    + +
    + + +
    +
    + )} + + } + +
    +
    + ); +}; + +export default LIstItems; diff --git a/src/components/MkdTrelloColumns/LinkifyText.tsx b/src/components/MkdTrelloColumns/LinkifyText.tsx new file mode 100644 index 0000000..e71c07d --- /dev/null +++ b/src/components/MkdTrelloColumns/LinkifyText.tsx @@ -0,0 +1,55 @@ +import React from "react"; + +const LinkifyText = ({ comment, attachment }) => { + + return ( +
    +
    + {" "} + {attachment && ( + + + + + + )} +
    + {comment + ? JSON.parse(comment).map((com, i) => ( + + {com.match(/\(([^)]+)\)/) ? ( + <> + {com.split("[")[0]} + + {com.match(/(?<=\[).*?(?=\])/g)[0]} + + {com.split(")")[1]} + + ) : ( + com + )} +
    +
    + )) + : "N/A"} +
    + ); +}; + +export default LinkifyText; diff --git a/src/components/MkdTrelloColumns/ListSetting.tsx b/src/components/MkdTrelloColumns/ListSetting.tsx new file mode 100644 index 0000000..7c000ff --- /dev/null +++ b/src/components/MkdTrelloColumns/ListSetting.tsx @@ -0,0 +1,351 @@ +import React from "react"; +import { useParams } from "react-router"; +import AlartMolad from "./AlartMolad"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +const ListSetting = ({ cardFormShow, setCardFormShow, list, getData }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [showModal, setShowModal] = React.useState(false); + const [showMoveListModal, setShowMoveListModal] = React.useState(false); + const [showNameChangeModal, setShowNameChangeModal] = React.useState(false); + const [showDeleteModal, setShowDeleteModal] = React.useState(false); + const [showArchiveModal, setShowArchiveModal] = React.useState(false); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [listName, setListName] = React.useState(list.title); + + const { id } = useParams(); + + async function getLists() { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists?order_by=id&direction=asc`, + {}, + "GET" + ); + + const { list } = result; + setCurrentTableData(list); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + const updateListPosition = async (listId) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists/${list.status}`, + { + position: listId, + }, + "PUT" + ); + if (!result.error) { + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const updateListName = async () => { + let sdk = new MkdSDK(); + if (listName) { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${id}/lists/${list.status}`, + { + name: listName, + }, + "PUT" + ); + if (!result.error) { + getData(); + setShowNameChangeModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } else { + showToast(globalDispatch, "Enter Name"); + } + }; + + const deleteList = async () => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}`, + {}, + "DELETE" + ); + + if (!result.error) { + getData(); + setShowDeleteModal(false); + setShowModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const archiveList = async () => { + let sdk = new MkdSDK(); + if (listName) { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list.status}`, + { + archive: true, + }, + "DELETE" + ); + if (!result.error) { + getData(); + setShowArchiveModal(false); + setShowModal(false); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } else { + showToast(globalDispatch, "Enter Name"); + } + }; + + React.useEffect(() => { + (async function () { + await getLists(); + })(); + }, []); + + return ( + <> + + {showModal && ( +
    +
    setShowModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + List actions + +
    +
      +
    • { + setCardFormShow(!cardFormShow); + setShowModal(false); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Add Card... +
    • +
    • { + setShowMoveListModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Move List... +
    • +
    • { + setShowNameChangeModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Change Name +
    • +
    • { + setShowDeleteModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Delete +
    • +
    • { + setShowArchiveModal(true); + }} + className=" cursor-pointer px-[12px] py-[6px] text-[#172b4d] hover:bg-[#ceecfc5d] " + > + Archive +
    • +
    +
    +
    + )} + {showMoveListModal && ( +
    +
    setShowMoveListModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + Move + +
    +
    + + +
    +
    +
    + )} + {showNameChangeModal && ( +
    +
    setShowNameChangeModal(false)} + className=" absolute left-0 top-0 h-full w-full bg-[#0000004f] " + /> +
    +
    + Change Name + +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +
    + )} + {showDeleteModal && ( + + )} + {showArchiveModal && ( + + )} + + ); +}; + +export default ListSetting; diff --git a/src/components/MkdTrelloColumns/Lists.tsx b/src/components/MkdTrelloColumns/Lists.tsx new file mode 100644 index 0000000..2f5e9a3 --- /dev/null +++ b/src/components/MkdTrelloColumns/Lists.tsx @@ -0,0 +1,126 @@ +import React from "react"; +import { useDrag, useDrop } from "react-dnd"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; +import LIstItems from "./LIstItems"; + +const style = { + border: "1px dashed gray", + padding: "0.5rem 1rem", + marginBottom: ".5rem", + backgroundColor: "white", + cursor: "move", +}; + +const ItemTypes = { + CARD: "card", +}; +const icons = { 1: "⭕️", 2: "🔆️", 3: "📝", 4: "✅" }; + +const Lists = ({ + list, + getData, + statuses, + items, + setItems, + moveList, + setCurrentTableData, + id, + index, +}) => { + const { dispatch } = React.useContext(AuthContext); + const [cardItems, setCardItems] = React.useState([]); + const ref = React.useRef(null); + const [{ handlerId }, drop] = useDrop({ + accept: ItemTypes.CARD, + collect(monitor) { + return { + handlerId: monitor.getHandlerId(), + }; + }, + hover(item, monitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + if (dragIndex === hoverIndex) { + return; + } + const hoveredRect = ref.current.getBoundingClientRect(); + const hoverMiddleY = (hoveredRect.bottom - hoveredRect.top) / 2; + const mousePosition = monitor.getClientOffset(); + const hoverClientY = mousePosition.y - hoveredRect.top; + + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + moveList(dragIndex, hoverIndex); + item.index = hoverIndex; + }, + }); + const [{ isDragging }, drag] = useDrag({ + type: ItemTypes.CARD, + item: { type: ItemTypes.CARD, id, index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + const opacity = isDragging ? 0 : 1; + drag(drop(ref)); + + const getCardsByList = async () => { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/lists/${list?.status}/cards`, + {}, + "GET" + ); + let cardsList = []; + result.list.map((item) => + cardsList.push({ + id: item.id, + icon: icons[item.list_id], + status: item.list_id, + title: "Human Interest Form", + content: item.name, + }) + ); + setCardItems(cardsList); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + (async function () { + await getCardsByList(); + })(); + }, [list?.status]); + + return ( +
    + +
    + ); +}; + +export default Lists; diff --git a/src/components/MkdTrelloColumns/MkdTrelloColumns.tsx b/src/components/MkdTrelloColumns/MkdTrelloColumns.tsx new file mode 100644 index 0000000..1ca9893 --- /dev/null +++ b/src/components/MkdTrelloColumns/MkdTrelloColumns.tsx @@ -0,0 +1,59 @@ +import React from "react"; +import { HTML5Backend } from "react-dnd-html5-backend"; +import { DndProvider } from "react-dnd"; +import BoardCardsPage from "./BoardCardsPage"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import MkdSDK from "@/utils/MkdSDK"; + +const icons = { 1: "⭕️", 2: "🔆️", 3: "📝", 4: "✅" }; + +const MkdTrelloColumns = () => { + const { dispatch } = React.useContext(AuthContext); + const [currentTableData, setCurrentTableData] = React.useState([]); + + async function getData() { + let sdk = new MkdSDK(); + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/boards/${0}/lists?order_by=id&direction=asc`, + {}, + "GET" + ); + + const { list } = result; + let lists = []; + list.map((item) => + lists.push({ + status: item.id, + title: item.name, + icon: icons[item.id], + color: "#EB5A46", + position: item.position, + }) + ); + setCurrentTableData(lists); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + React.useEffect(() => { + (async function () { + await getData(); + })(); + }, []); + + return ( +
    + + + +
    + ); +}; + +export default MkdTrelloColumns; diff --git a/src/components/MkdTrelloColumns/Window.tsx b/src/components/MkdTrelloColumns/Window.tsx new file mode 100644 index 0000000..f947a8f --- /dev/null +++ b/src/components/MkdTrelloColumns/Window.tsx @@ -0,0 +1,270 @@ +import React from "react"; +import Modal from "react-modal"; +import AttachmentCard from "./AttachmentCard"; +import CardMember from "./CardMember"; +import Comment from "./Comment"; +import CommentForm from "./CommentForm"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const Window = ({ show, onClose, item }) => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [currentTableData, setCurrentTableData] = React.useState({}); + const [attachmentsList, setAttachmentsList] = React.useState([]); + const [commentsList, setCommentsList] = React.useState([]); + + async function getData() { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}`, + {}, + "GET" + ); + const result2 = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/attachments?order_by=id&direction=asc`, + {}, + "GET" + ); + setAttachmentsList(result2.list); + const { model } = result; + setCurrentTableData(model); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + async function getComment() { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/comments?order_by=id&direction=desc&limit=20`, + {}, + "GET" + ); + + setCommentsList(result.list); + } catch (error) { + tokenExpireError(dispatch, error.message); + } + } + + React.useEffect(() => { + (async function () { + await getData(); + })(); + (async function () { + await getComment(); + })(); + }, []); + + const attachmentHanle = async (e) => { + try { + let formData = new FormData(); + formData.append("file", e.target.files[0]); + const attachment = await sdk.uploadImage(formData); + + if (attachment.url) { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/cards/${item.id}/attachments`, + { + name: e.target.files[0].name, + attachment: attachment.url, + }, + "POST" + ); + + if (!result.error) { + showToast(globalDispatch, "Added"); + getData(); + } + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + const deleteAttachment = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/attachments/${id}`, + {}, + "DELETE" + ); + + if (!result.error) { + getData(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + const deleteComment = async (id) => { + try { + const result = await sdk.callRawAPI( + `/v2/api/lambda/pm/comments/${id}`, + {}, + "DELETE" + ); + + if (!result.error) { + getComment(); + } + } catch (error) { + tokenExpireError(dispatch, error.message); + } + }; + + Modal.setAppElement("body"); + + return ( + +
    +

    + {currentTableData.name} +

    + +
    +
    +

    {item.content}

    + +

    {/* {item.name} */}

    +
    + + + +
    + +
    + {attachmentsList.length > 0 ? ( +
    +

    + + + + attachments +

    +
    + ) : ( +
    + +

    + add attachment +

    +
    + )} + + {attachmentsList?.map((attach, i) => ( + + ))} + {attachmentsList.length > 0 && ( + + )} +
    + +
    +
    + + + +

    Comments

    +
    + + + + {commentsList.length > 0 && + commentsList?.map((com, i) => ( + + ))} +
    +
    + ); +}; + +export default Window; diff --git a/src/components/MkdTrelloColumns/data/index.ts b/src/components/MkdTrelloColumns/data/index.ts new file mode 100644 index 0000000..2c88afe --- /dev/null +++ b/src/components/MkdTrelloColumns/data/index.ts @@ -0,0 +1,50 @@ +const data = [{ + id: 1, + icon: "⭕️", + status: "open", + title: "Human Interest Form", + content: "Fill out human interest distribution form" +}, { + id: 2, + icon: "⭕️", + status: "open", + title: "Purchase present", + content: "Get an anniversary gift" +}, { + id: 3, + icon: "⭕️", + status: "open", + title: "Invest in investments", + content: "Call the bank to talk about investments" +}, { + id: 4, + icon: "⭕️", + status: "open", + title: "Daily reading", + content: "Finish reading Intro to UI/UX" +}]; + +const statuses = [{ + status: "open", + title: "To do", + icon: "⭕️", + color: "#EB5A46" +}, { + status: "in progress", + title: "in progress", + icon: "🔆️", + color: "#00C2E0" +}, { + status: "in review", + title: "in review", + icon: "📝", + color: "#C377E0" +}, { + status: "done", + title: "done", + icon: "✅", + color: "#3981DE" +}]; + + +export { data, statuses }; \ No newline at end of file diff --git a/src/components/MkdTrelloColumns/data/types.ts b/src/components/MkdTrelloColumns/data/types.ts new file mode 100644 index 0000000..9af16c6 --- /dev/null +++ b/src/components/MkdTrelloColumns/data/types.ts @@ -0,0 +1,3 @@ +const ITEM_TYPE = "ITEM"; + +export default ITEM_TYPE; \ No newline at end of file diff --git a/src/components/MkdTrelloColumns/index.ts b/src/components/MkdTrelloColumns/index.ts new file mode 100644 index 0000000..871cdad --- /dev/null +++ b/src/components/MkdTrelloColumns/index.ts @@ -0,0 +1,25 @@ +import { lazy } from "react"; + +export const AlartMolad = lazy(() => import("./AlartMolad")); +export const AttachmentCard = lazy(() => import("./AttachmentCard")); +export const AttachmentViewer = lazy(() => import("./AttachmentViewer")); +export const BoardCardsPage = lazy(() => import("./BoardCardsPage")); +export const CardMember = lazy(() => import("./CardMember")); +export const CardMemberCard = lazy(() => import("./CardMemberCard")); +export const Col = lazy(() => import("./Col")); +// export const Comment copy = lazy(() => import("./Comment copy")); +export const Comment = lazy(() => import("./Comment")); +// export const CommentForm copy = lazy(() => import("./CommentForm copy")); +export const CommentForm = lazy(() => import("./CommentForm")); +// export const CommentReplyBox copy = lazy(() => import("./CommentReplyBox copy")); +export const CommentReplyBox = lazy(() => import("./CommentReplyBox")); +export const CreateNewRoomModal = lazy(() => import("./CreateNewRoomModal")); +export const DropWrapper = lazy(() => import("./DropWrapper")); +export const InstandEditor = lazy(() => import("./InstandEditor")); +export const Item = lazy(() => import("./Item")); +export const LinkifyText = lazy(() => import("./LinkifyText")); +export const LIstItems = lazy(() => import("./LIstItems")); +export const Lists = lazy(() => import("./Lists")); +export const ListSetting = lazy(() => import("./ListSetting")); +export const MkdTrelloColumns = lazy(() => import("./MkdTrelloColumns")); +export const Window = lazy(() => import("./Window")); diff --git a/src/components/MkdWizardContainer/MkdWizardContainer.tsx b/src/components/MkdWizardContainer/MkdWizardContainer.tsx new file mode 100644 index 0000000..13c21cb --- /dev/null +++ b/src/components/MkdWizardContainer/MkdWizardContainer.tsx @@ -0,0 +1,53 @@ +import React, { useState } from "react"; + +const MkdWizardContainer = ({ children, className }) => { + const [activeId, setActiveId] = useState(1); + + const childrenArray = React.Children.toArray(children); + + const activeIndex = childrenArray.findIndex( + (child) => child.props.componentId === activeId + ); + + const handlePreviousClick = () => { + const newIndex = activeIndex - 1; + if (newIndex >= 0) { + setActiveId(childrenArray[newIndex].props.componentId); + } + }; + + const handleNextClick = () => { + const newIndex = activeIndex + 1; + if (newIndex < childrenArray.length) { + setActiveId(childrenArray[newIndex].props.componentId); + } + }; + + return ( +
    +
    + {childrenArray.map((child) => + child.props.componentId === activeId ? child : null + )} +
    +
    + + +
    +
    + ); +}; + +export default MkdWizardContainer; diff --git a/src/components/MkdWizardContainer/index.ts b/src/components/MkdWizardContainer/index.ts new file mode 100644 index 0000000..20a74c2 --- /dev/null +++ b/src/components/MkdWizardContainer/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdWizardContainer = lazy(() => import("./MkdWizardContainer")); diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx new file mode 100644 index 0000000..1cd9161 --- /dev/null +++ b/src/components/Modal/Modal.tsx @@ -0,0 +1,117 @@ +import { StringCaser } from "@/utils/utils"; +import { memo, ReactNode, useEffect, useRef } from "react"; +import { MdClose } from "react-icons/md"; + +export type ModalClassType = { + modalDialog?: string; + modal?: string; + modalContent?: string; +}; + +interface ModalProps { + isOpen: boolean; + zIndex?: string | number; + disableCancel?: boolean; + children: ReactNode; + title: ReactNode | string; + modalCloseClick: () => void; + modalHeader: boolean; + classes: ModalClassType; + page?: string; +} + +const Modal = ({ + title, + isOpen, + zIndex, + children, + page = "", + modalHeader, + modalCloseClick, + disableCancel = false, + classes = { modal: "h-full", modalDialog: "h-[90%]", modalContent: "" }, +}: ModalProps) => { + const modalRef = useRef(null); + + // useEffect(() => { + // if (isOpen) { + // document.body.style.overflow = "hidden"; + // } else { + // document.body.style.overflow = "auto"; + // } + // }, [isOpen]); + + useEffect(() => { + const scrollableElements = document.querySelectorAll( + "body, .scrollable-container" // Add other selectors if needed + ); + + if (isOpen) { + scrollableElements.forEach((element) => { + element.style.overflow = "hidden"; + }); + } else { + scrollableElements.forEach((element) => { + element.style.overflow = "auto"; + }); + } + + return () => { + scrollableElements.forEach((element) => { + element.style.overflow = "auto"; + }); + }; + }, [isOpen]); + + return ( +
    +
    + {modalHeader && ( +
    +
    + {["string"].includes(typeof title) + ? StringCaser(title as string, { casetype: "capitalize", separator: " " }) + : title} +
    + {disableCancel ? null : ( + + )} +
    + )} + +
    + {children} +
    +
    +
    + ); +}; + +const ModalMemo = memo(Modal); +export { ModalMemo as Modal }; diff --git a/src/components/Modal/ModalAlert.tsx b/src/components/Modal/ModalAlert.tsx new file mode 100644 index 0000000..a579365 --- /dev/null +++ b/src/components/Modal/ModalAlert.tsx @@ -0,0 +1,56 @@ + +// import { Close, danger, warning } from 'Assets/svgs' +import React from 'react' + + +const ModalAlert = ( { closeModalFunction, message, title, messageClasses, titleClasses, buttonText = "OK" } ) => { + return ( + + ) +} + +export default ModalAlert diff --git a/src/components/Modal/ModalPrompt.tsx b/src/components/Modal/ModalPrompt.tsx new file mode 100644 index 0000000..adc843c --- /dev/null +++ b/src/components/Modal/ModalPrompt.tsx @@ -0,0 +1,98 @@ +import React from "react"; +import { CloseIcon, DangerIcon } from "@/assets/svgs"; +import { InteractiveButton } from "@/components/InteractiveButton"; + +// type Props = { +// closeModalFunction: () => void +// actionHandler: any +// message?: string +// title?: string +// rejectText?: string +// acceptText?: string +// titleClasses?: string +// messageClasses?: string +// } + +const ModalPrompt = ({ + open, + closeModalFunction, + actionHandler, + message, + title, + messageClasses, + titleClasses, + acceptText = "", + rejectText = "Cancel", + loading = false, + allowAccept = true, +}) => { + return ( + + ); +}; + +export default ModalPrompt; + diff --git a/src/components/Modal/index.ts b/src/components/Modal/index.ts new file mode 100644 index 0000000..2bf878f --- /dev/null +++ b/src/components/Modal/index.ts @@ -0,0 +1,9 @@ +import { lazy } from "react"; + +export const Modal = lazy(() => + import("./Modal").then((module) => ({ default: module.Modal })) +); +export const ModalPrompt = lazy(() => import("./ModalPrompt")); +export const ModalAlert = lazy(() => import("./ModalAlert")); + +export { type ModalClassType } from "./Modal"; diff --git a/src/components/ModalPromptForm/ModalPromptForm.tsx b/src/components/ModalPromptForm/ModalPromptForm.tsx new file mode 100644 index 0000000..09289fe --- /dev/null +++ b/src/components/ModalPromptForm/ModalPromptForm.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { CloseIcon } from "@/assets/svgs"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +const ModalPrompt = ({ + closeModalFunction, + actionHandler, + title = "Add You Text", + titleClasses = "text-center font-bold text-lg", + acceptText = "Submit", + rejectText = "Close", + isInfo = false, +}) => { + const [loading, setLoading] = React.useState(false); + const schema = yup.object({ + message: yup.string(), + }); + + const { register, handleSubmit } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + setLoading(true); + try { + const result = await actionHandler(data.message); + closeModalFunction(); + setLoading(false); + } catch (error) { + setLoading(false); + closeModalFunction(); + } + }; + + return ( +
    +
    +
    +
    + {title ?
    {title}
    : null} +
    + +
    + +
    + +
    + +
    + + + {acceptText?.charAt(0)?.toUpperCase() + + acceptText?.slice(1)?.toLowerCase()} + +
    +
    +
    + ); +}; + +export default ModalPrompt; diff --git a/src/components/ModalPromptForm/index.ts b/src/components/ModalPromptForm/index.ts new file mode 100644 index 0000000..0a8140e --- /dev/null +++ b/src/components/ModalPromptForm/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const ModalPromptForm = lazy(() => import("./ModalPromptForm")); \ No newline at end of file diff --git a/src/components/ModalSidebar/ModalSidebar.tsx b/src/components/ModalSidebar/ModalSidebar.tsx new file mode 100644 index 0000000..c5b2652 --- /dev/null +++ b/src/components/ModalSidebar/ModalSidebar.tsx @@ -0,0 +1,153 @@ +import { MouseEventHandler, Ref, useEffect, useRef } from "react"; +import { BiLeftArrow, BiSolidLeftArrowAlt } from "react-icons/bi"; +import { RiArrowGoBackFill } from "react-icons/ri"; + +const justification = { + right: "justify-end", + left: "justify-start", +}; +const closed = { + right: "translate-x-full", + left: "-translate-x-full", +}; +const open = { + right: "-translate-x-0", + left: "-translate-x-0", +}; + +interface ModalSidebarProps { + customMinWidthInTw?: string; + isModalActive?: boolean; + closeModalFn: () => void; + children: React.ReactNode; + showHeader?: boolean; + title?: any; + headerClassName?: string; + headerContentClassName?: string; + headerContent?: React.ReactNode; + closePosition?: 1 | 2; + side?: "right" | "left"; + classes?: { + modalBody?: string; + }; +} + +const ModalSidebar = ({ + customMinWidthInTw = "min-w-full", + isModalActive = false, + closeModalFn = () => {}, + children, + showHeader = false, + title = "Modal", + headerClassName = "bg-primaryBlue", + headerContentClassName = "text-white", + headerContent = null, + closePosition = 1, + side = "right", + classes = { modalBody: "" }, +}: ModalSidebarProps) => { + const modalRef = useRef(null); + + // useEffect(() => { + // const handleClickOutside = (e) => { + // if (modalRef.current && !modalRef.current.contains(e.target)) { + // closeModalFn(); + // } + // }; + + // document.addEventListener("mousedown", handleClickOutside); + + // return () => { + // document.removeEventListener("mousedown", handleClickOutside); + // }; + // }, []); + + const onClose = (e: MouseEvent) => { + // e.preventDefault(); + const target = e.target as HTMLElement; + if (target.id === "modal") { + closeModalFn(); + } + }; + + useEffect(() => { + if (isModalActive && modalRef) { + modalRef?.current?.focus(); + } + }, [isModalActive]); + + return ( + + ); +}; + +export default ModalSidebar; diff --git a/src/components/ModalSidebar/index.ts b/src/components/ModalSidebar/index.ts new file mode 100644 index 0000000..5d5b5bd --- /dev/null +++ b/src/components/ModalSidebar/index.ts @@ -0,0 +1,2 @@ +import { lazy } from "react"; +export const ModalSidebar = lazy(() => import("./ModalSidebar")); diff --git a/src/components/MultiSelect/MultiSelect.tsx b/src/components/MultiSelect/MultiSelect.tsx new file mode 100644 index 0000000..ece9417 --- /dev/null +++ b/src/components/MultiSelect/MultiSelect.tsx @@ -0,0 +1,117 @@ +import React, { useCallback } from "react"; +import { memo } from "react"; +import { CheckIcon, PlusIcon } from "@heroicons/react/24/solid"; +import { MkdButton } from "@/components/MkdButton"; + +const MultiSelect = ({ + label, + options, + selected, + setSelected, + showIcons = true, +}) => { + const toggleOption = useCallback( + (option) => { + let temp = selected && selected?.length ? [...selected] : []; + const index = temp.findIndex((i) => i === option); + if (index > -1) { + temp.splice(index, 1); + if (setSelected) { + setSelected([...temp]); + } + } else { + temp.push(option); + if (setSelected) { + setSelected([...temp]); + } + } + }, + [selected] + ); + + const toggleAllOptions = useCallback(() => { + let temp = selected && selected?.length ? [...selected] : []; + if (temp?.length === options?.length) { + if (setSelected) { + setSelected([]); + } + } else { + if (setSelected) { + setSelected([...options]); + } + } + }, [selected]); + + const isAllSelected = () => { + return selected?.length === options?.length; + }; + + return ( +
    +
    +
    {label}
    +
    + +
    + toggleAllOptions()} + > + {"All"} + {showIcons && ( + <> + {isAllSelected() ? ( + + ) : ( + + )} + + )} + + {options.map((option, key) => { + const isSelected = selected?.includes(option); + return ( + toggleOption(option)} + > + {option} + {showIcons && ( + <> + {isSelected ? ( + + ) : ( + + )} + + )} + + ); + })} +
    +
    + ); +}; + +export default memo(MultiSelect); diff --git a/src/components/MultiSelect/index.ts b/src/components/MultiSelect/index.ts new file mode 100644 index 0000000..efc0547 --- /dev/null +++ b/src/components/MultiSelect/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const MultiSelect = lazy(() => import("./MultiSelect")); + + \ No newline at end of file diff --git a/src/components/MultipleAnswer/MultipleAnswer.tsx b/src/components/MultipleAnswer/MultipleAnswer.tsx new file mode 100644 index 0000000..75be5f1 --- /dev/null +++ b/src/components/MultipleAnswer/MultipleAnswer.tsx @@ -0,0 +1,74 @@ +import React, { useId, useState } from "react"; +import { PlusIcon, TrashIcon } from "@heroicons/react/24/solid"; + +const MultipleAnswer = () => { + const inputId = useId(); + const [inputValue, setInputValue] = useState([]); + const [currentValue, setCurrentValue] = useState(""); + + function handleInput(e) { + const inputValue = e.target.value; + setCurrentValue(inputValue); + } + + const handleValueInput = () => { + setInputValue((prev) => [currentValue, ...prev]); + setCurrentValue(""); + }; + const handleKeyDown = (e) => { + if (e.key === "Enter") { + handleValueInput(); + } + }; + + return ( + <> +
    +
    +
    + handleInput(e)} + onKeyDown={(e) => handleKeyDown(e)} + value={currentValue} + className="block w-full rounded-lg border border-blue-600 bg-white p-4 pl-3 text-sm text-black placeholder-black focus:border-blue-500 focus:ring-blue-500 dark:text-gray-400 dark:placeholder-gray-400" + /> + + + +
    + {inputValue?.length > 0 && + inputValue.map((input) => { + return ( +
    + {input} + + setInputValue((prev) => prev.filter((p) => p != input)) + } + > + + +
    + ); + })} +
    +
    + + ); +}; + +export default MultipleAnswer; diff --git a/src/components/MultipleAnswer/index.ts b/src/components/MultipleAnswer/index.ts new file mode 100644 index 0000000..4902be8 --- /dev/null +++ b/src/components/MultipleAnswer/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const MultipleAnswer = lazy(() => import("./MultipleAnswer")); + + \ No newline at end of file diff --git a/src/components/Notifications/NotificationItem.tsx b/src/components/Notifications/NotificationItem.tsx new file mode 100644 index 0000000..4b5c17d --- /dev/null +++ b/src/components/Notifications/NotificationItem.tsx @@ -0,0 +1,78 @@ +import React, { useState } from 'react' + +const NotificationItem = ({ type, mainText, title, time, isRead = false }) => { + const [markAsRead, setMarkAsRead] = useState(isRead); + return ( +
    +
    + { + type === "success" ? ( + + + + ) : type === "error" ? ( + + + + ) : type === "info" ? ( + + + + ) : type === "warning" ? ( + + + + ) : ( + + + + ) + } +
    +
    +
    + {title} +
    + {!markAsRead && } + {time} + + +
      + {/*
    • + + + + + + Delete +
    • */} +
    • setMarkAsRead(true)} + > + + + + + + Mark as read +
    • +
    +
    +
    +
    + +
    {mainText}
    +
    Details
    +
    +
    + ) +} + +export default NotificationItem \ No newline at end of file diff --git a/src/components/Notifications/Notifications.tsx b/src/components/Notifications/Notifications.tsx new file mode 100644 index 0000000..2947bfc --- /dev/null +++ b/src/components/Notifications/Notifications.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import NotificationItem from './NotificationItem' + +const MOCK_DATA = [ + { + id: 1, + type: "info", + mainText: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Totam neque quasi aperiam temporibus. Minus, veniam?", + title: "Info Notification", + time: "5 min ago" + }, + { + id: 2, + type: "warning", + mainText: "Dolor sit amet consectetur adipisicing elit. Totam neque quasi aperiam temporibus. Minus, veniam?", + title: "Warning Notification", + time: "10 min ago", + isRead: true, + }, + { + id: 3, + type: "error", + mainText: "Sit amet consectetur adipisicing elit. Totam neque quasi aperiam temporibus. Minus, veniam?", + title: "Error Notification", + time: "15 min ago" + }, + { + id: 4, + type: "success", + mainText: "Amet consectetur adipisicing elit. Totam neque quasi aperiam temporibus. Minus, veniam?", + title: "Success Notification", + time: "20 min ago" + }, + { + id: 5, + type: "info", + mainText: "Consectetur adipisicing elit. Totam neque quasi aperiam temporibus. Minus, veniam?", + title: "Info Notification", + time: "25 min ago", + isRead: true, + } +] + +const Notifications = ({ setSidebar }) => { + return ( +
    +
    +
    + setSidebar(false)} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"> + + + Notifications (3) +
    +
    +
    + { + MOCK_DATA.map(item => ( + + )) + } +
    +
    + ) +} + +export default Notifications \ No newline at end of file diff --git a/src/components/Notifications/index.ts b/src/components/Notifications/index.ts new file mode 100644 index 0000000..771b9cf --- /dev/null +++ b/src/components/Notifications/index.ts @@ -0,0 +1 @@ +export { default as Notifications } from "./Notifications" \ No newline at end of file diff --git a/src/components/PaginationBar/LimitSelect.tsx b/src/components/PaginationBar/LimitSelect.tsx new file mode 100644 index 0000000..91b00f9 --- /dev/null +++ b/src/components/PaginationBar/LimitSelect.tsx @@ -0,0 +1,47 @@ +import React, { useMemo } from "react"; + +const LimitSelect = ({ + updatePageSize, + pageSize, + startSize, + multiplier, + canChangeLimit = true, +}) => { + const startSizeMemo = useMemo(() => startSize, [startSize]); + const multiplierMemo = useMemo(() => multiplier, [multiplier]); + + return ( + <> + {startSizeMemo ? ( + + ) : null} + + ); +}; + +export default LimitSelect; diff --git a/src/components/PaginationBar/PaginationBar.tsx b/src/components/PaginationBar/PaginationBar.tsx new file mode 100644 index 0000000..5fc3af2 --- /dev/null +++ b/src/components/PaginationBar/PaginationBar.tsx @@ -0,0 +1,288 @@ +import { + NarrowUpArrowIcon, +} from "@/assets/svgs"; +import { useState } from "react"; +import { LimitSelect } from "./index"; +import { MkdPopover } from "@/components/MkdPopover"; +import { LazyLoad } from "@/components/LazyLoad"; + +const PaginationBar = ({ + currentPage, + pageCount, + pageSize, + canPreviousPage, + canNextPage, + updatePageSize, + previousPage, + nextPage, + startSize = 500, + multiplier = 100, + updateCurrentPage, + canChangeLimit = true, +}) => { + const theNumber = 16; + const [showAboveFive, setShowAboveFive] = useState(false); + + return ( +
    + {/*
    +
    + + Page{" "} + + {+currentPage} of {pageCount} + {" "} + +
    + +
    */} +
    +
    + + Page{" "} + + {+currentPage} of {pageCount} + {" "} + +
    +
    + +
    +
    + +
    + + {/* */} + + {showAboveFive ? ( + + ) : null} + +
    + {pageCount !== undefined && + Array.from({ length: Number(pageCount) }).map((_, index) => { + const page = index + 1; + + if ( + (!showAboveFive && pageCount <= 5) || + (!showAboveFive && pageCount <= 7) + ) { + return ( + + ); + } + if (!showAboveFive && pageCount > 5 && page <= 5) { + return ( + + ); + } + if ( + pageCount > 5 && + pageCount >= 8 && + page > 5 && + page < 7 && + !showAboveFive + ) { + return ( + + setShowAboveFive(true)} + > + ... + + } + backgroundColor="#FFF0E5" + tooltipClasses={`items-center flex flex-col gap-2 h-[31.25rem] min-h-[31.25rem] max-h-[31.25rem] w-fit min-w-fit max-w-fit overflow-auto`} + > + {pageCount !== undefined && + Array.from({ length: Number(pageCount) }).map( + (_, index) => { + const page = index + 1; + if (page > 5) { + return ( + + ); + } + } + )} + + + ); + } + if ( + !showAboveFive && + pageCount > 5 && + pageCount >= 8 && + page === 7 + ) { + return ( + + ); + } + + // if ( + // showAboveFive && + // pageCount > 5 && + // pageCount >= 8 && + // page > 5 + // ) { + // return ( + // + // ); + // } + // return ( + // + // ); + })} +
    + + {/* */} + +
    + {/* */} + + {/*
    + +
    */} +
    + ); +}; + +export default PaginationBar; +//
    +// {" "} +// {" "} +//
    diff --git a/src/components/PaginationBar/deprecated_PaginationBar.tsx b/src/components/PaginationBar/deprecated_PaginationBar.tsx new file mode 100644 index 0000000..1843803 --- /dev/null +++ b/src/components/PaginationBar/deprecated_PaginationBar.tsx @@ -0,0 +1,59 @@ +import React from "react"; +const PaginationBar = ({ + currentPage, + pageCount, + pageSize, + canPreviousPage, + canNextPage, + updatePageSize, + previousPage, + nextPage, + startsForm0 = false, +}) => { + return ( + <> +
    +
    + + Page{" "} + + {+currentPage + (startsForm0 ? 1 : 0)} of {Math.ceil(pageCount)} + {" "} + + +
    + {/* */} +
    + {" "} + {" "} +
    +
    + + ); +}; + +export default PaginationBar; diff --git a/src/components/PaginationBar/index.ts b/src/components/PaginationBar/index.ts new file mode 100644 index 0000000..73847a5 --- /dev/null +++ b/src/components/PaginationBar/index.ts @@ -0,0 +1,4 @@ +import { lazy } from "react"; + +export const LimitSelect = lazy(() => import("./LimitSelect")); +export const PaginationBar = lazy(() => import("./PaginationBar")); diff --git a/src/components/PreWireframeTabs/ApiSection.tsx b/src/components/PreWireframeTabs/ApiSection.tsx new file mode 100644 index 0000000..b45d44d --- /dev/null +++ b/src/components/PreWireframeTabs/ApiSection.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const ApiSection = () => { + return ( +
    +
    Amplify API Creation With GPT
    + +
    + + +
    +
    + ) +} + +export default ApiSection \ No newline at end of file diff --git a/src/components/PreWireframeTabs/DbSchema.tsx b/src/components/PreWireframeTabs/DbSchema.tsx new file mode 100644 index 0000000..f83c545 --- /dev/null +++ b/src/components/PreWireframeTabs/DbSchema.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const DbSchema = () => { + return ( +
    +
    Create and Modify Your Database Schema Here
    + +
    + + +
    +
    + ) +} + +export default DbSchema \ No newline at end of file diff --git a/src/components/PreWireframeTabs/Docs.tsx b/src/components/PreWireframeTabs/Docs.tsx new file mode 100644 index 0000000..9ca53c2 --- /dev/null +++ b/src/components/PreWireframeTabs/Docs.tsx @@ -0,0 +1,254 @@ +import { Skeleton } from "@/components/Skeleton"; +import SkeletonLoader from "@/components/Skeleton/Skeleton"; +import { GlobalContext, showToast } from "@/context/Global"; +import MkdSDK from "@/utils/MkdSDK"; +import React from "react"; +import { pdfjs, Document, Page } from "react-pdf"; +import "react-pdf/dist/esm/Page/AnnotationLayer.css"; +import "react-pdf/dist/esm/Page/TextLayer.css"; +import { MdFullscreen } from "react-icons/md"; +import { useSearchParams } from "react-router-dom"; + +// pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`; + +pdfjs.GlobalWorkerOptions.workerSrc = new URL( + "pdfjs-dist/build/pdf.worker.min.js", + import.meta.url +).toString(); + +const options = { + cMapUrl: "/cmaps/", + standardFontDataUrl: "/standard_fonts/", +}; + +const Docs = ({ + width, + height, + url = "", + saveData, + loading, + isLoadingPdf, + setIsLoadingPdf, + setIsFullView, + numPages, + pageNumber, + iframeRef, + previousPage, + nextPage, + fileUrl, + onDocumentLoadSuccess, + pdfLoadSuccess, + changePage, + isCreateSection, + changedPdf, + setChangedPdf, + saveTranscribeLoading, +}) => { + const [fileObj, setFileObj] = React.useState({}); + const [isUpdating, setIsUpdating] = React.useState(false); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [typedValue, setTypedValue] = React.useState(null); + const [searchParams] = useSearchParams(); + const pdfParam = searchParams.get("pdf"); + + const pdf_url = + (url?.includes("pdf_file") ? JSON.parse(url)?.pdf_file : url) ?? null; + + const previewImage = async (field, target) => { + let tempFileObj = fileObj; + const fileName = target.files[0].name; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + setChangedPdf(true); + await submitPdf(fileName); + }; + + const submitPdf = async (fileName) => { + let sdk = new MkdSDK(); + setIsUpdating(true); + // setIsLoadingPdf(true); + try { + let imgUrl; + let formData = new FormData(); + formData.append("file", fileObj["pdf_file"].file); + let uploadResult = await sdk.uploadImage(formData); + imgUrl = uploadResult.url; + saveData("pdf_file", imgUrl, fileName); + + // showToast(globalDispatch, "Changed PDF"); + } catch (error) { + showToast(globalDispatch, "Failed to change PDF"); + } finally { + setIsUpdating(false); + setIsLoadingPdf(false); + } + }; + + const handlePageNumChange = (event) => { + let value = event.target.value.replace(/\D/g, ""); + value = Number(value); + if (Number(numPages) < value) { + setTypedValue(Number(numPages)); + } else { + setTypedValue(value); + } + + if (event.key === "Enter") { + changePage(value, "input"); + setTypedValue(null); + } + }; + + return ( + <> + {changedPdf && (isLoadingPdf || loading) ? ( + + ) : pdf_url?.length ? ( +
    +
    + {/* {loading && !iframeRef.current && < SkeletonLoader />} */} + {/* */} + {/* */} + {pdfLoadSuccess ? ( +
    +
    + +
    + Page + handlePageNumChange(e)} + onKeyDown={(e) => handlePageNumChange(e)} + className="flex w-[50px] items-center rounded-md border border-[#C6C6C6] bg-white px-3 text-center placeholder-slate-950 shadow-sm" + disabled={saveTranscribeLoading} + /> + {`of ${numPages || "--"}`} +
    + + +
    +
    + +
    +
    + ) : ( + <> + )} + +
    + + } + height={height} + width={width} + > + } + pageNumber={pageNumber} + height={height - 100} + width={width} + /> + +
    +
    + +
    +
    +
    + ) : ( +
    + +
    + )} + + ); +}; + +export default Docs; diff --git a/src/components/PreWireframeTabs/PDFViewer.tsx b/src/components/PreWireframeTabs/PDFViewer.tsx new file mode 100644 index 0000000..3d47f8f --- /dev/null +++ b/src/components/PreWireframeTabs/PDFViewer.tsx @@ -0,0 +1,238 @@ +import SkeletonLoader from "@/components/Skeleton/Skeleton"; +import React, { useRef, useState } from "react"; +import { pdfjs, Document, Page } from "react-pdf"; +import "react-pdf/dist/esm/Page/AnnotationLayer.css"; +import "react-pdf/dist/esm/Page/TextLayer.css"; +import { TiZoomIn, TiZoomOut } from "react-icons/ti"; +import { MdFullscreenExit } from "react-icons/md"; + +pdfjs.GlobalWorkerOptions.workerSrc = new URL( + "pdfjs-dist/build/pdf.worker.min.js", + import.meta.url +).toString(); + +const options = { + cMapUrl: "/cmaps/", + standardFontDataUrl: "/standard_fonts/", +}; + +const MIN_SCALE = 1.0; // Define a minimum scale value + +const PDFViewer = ({ + setIsFullView, + numPages, + pageNumber, + iframeRef, + previousPage, + nextPage, + fileUrl, + onDocumentLoadSuccess, + changePage, + saveTranscribeLoading, + isFullView, +}) => { + const [scale, setScale] = React.useState(1); + const [typedValue, setTypedValue] = React.useState(null); + const [isScrolling, setIsScrolling] = useState(false); + const [scrollPosition, setScrollPosition] = useState({ left: 0, top: 0 }); + const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); + const scrollerRef = useRef(null); + + const changeZoom = (newScale) => { + if (newScale < MIN_SCALE) { + newScale = MIN_SCALE; // Ensure the scale does not go below the minimum + } + setScale(newScale); + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }; + + + + const toggleScrolling = (isEnable) => { + setIsScrolling(isEnable); + if (isEnable) { + window.addEventListener("mousemove", onMouseMove); + window.addEventListener("mouseup", onMouseUp); + } else { + window.removeEventListener("mousemove", onMouseMove); + } + }; + + const onMouseMove = (event) => { + const { clientX, clientY } = event; + const { left, top } = scrollerRef.current.getBoundingClientRect(); + const deltaX = (clientX - mousePosition.x) / scale; // Adjust for scale + const deltaY = (clientY - mousePosition.y) / scale; // Adjust for scale + setMousePosition({ x: clientX, y: clientY }); + setScrollPosition((prevScrollPosition) => ({ + left: prevScrollPosition.left + deltaX, + top: prevScrollPosition.top + deltaY, + })); + scrollerRef.current.scrollLeft = scrollPosition.left + deltaX; + scrollerRef.current.scrollTop = scrollPosition.top + deltaY; + }; + + const onMouseUp = () => { + setIsScrolling(false); + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("mouseup", onMouseUp); + }; + + const onMouseDown = (event) => { + const { scrollLeft, scrollTop } = scrollerRef.current; + setScrollPosition({ left: scrollLeft, top: scrollTop }); + setMousePosition({ x: event.clientX, y: event.clientY }); + toggleScrolling(true); + }; + + const handleKeyDown = (event) => { + if (event.key === "Escape") { + setIsFullView(false); + } + }; + document.addEventListener("keydown", handleKeyDown); + + if (isFullView) { + const intervel = setInterval(() => { + setTimeout(() => { + if (document.fullscreenElement) { + setIsFullView(true); + } else { + setIsFullView(false); + clearInterval(intervel); + } + }, 50); + }, 800); + } + + const handlePageNumChange = (event) => { + let value = event.target.value.replace(/\D/g, ""); + value = Number(value); + if (Number(numPages) < value) { + setTypedValue(Number(numPages)); + } else { + setTypedValue(value); + } + + if (event.key === "Enter") { + changePage(value, "input"); + setTypedValue(null); + } + }; + + const onDoubleClick = (event) => { + event.preventDefault(); + } + + return ( +
    +
    + + + +
    +
    + +
    + Page + handlePageNumChange(e)} + onKeyDown={(e) => handlePageNumChange(e)} + className="!z-20 flex w-[50px] items-center rounded-md border border-[#C6C6C6] bg-white px-3 text-center placeholder-slate-950 shadow-sm" + disabled={saveTranscribeLoading} + /> + {`of ${numPages || "--"}`} +
    + + +
    + +
    +
    + } + onDoubleClick={onDoubleClick} + > + } + onDoubleClick={onDoubleClick} + /> + +
    +
    +
    + ); +}; + +export default PDFViewer; diff --git a/src/components/PreWireframeTabs/TextareaTab.tsx b/src/components/PreWireframeTabs/TextareaTab.tsx new file mode 100644 index 0000000..4441b6a --- /dev/null +++ b/src/components/PreWireframeTabs/TextareaTab.tsx @@ -0,0 +1,31 @@ +import React from 'react' + +const TextareaTab = ( + { + headerText = "", + textAreaValue = "", + textAreaOnChange = () => { }, + secondaryBtnText = "", + secondaryBtnClickFn = () => { }, + primaryBtnText = "Save", + primaryBtnClickFn = () => { }, + } +) => { + return ( +
    +
    {headerText}
    + +
    + + +
    +
    + + ) +} + +export default TextareaTab; \ No newline at end of file diff --git a/src/components/PreWireframeTabs/Transcribe.tsx b/src/components/PreWireframeTabs/Transcribe.tsx new file mode 100644 index 0000000..8a1e47d --- /dev/null +++ b/src/components/PreWireframeTabs/Transcribe.tsx @@ -0,0 +1,979 @@ +import React, { useContext, useEffect, useState } from "react"; +import AudioFileIcon from "@/assets/svgs/AudioFileIcon"; +import { FaCaretDown, FaCodeMerge } from "react-icons/fa6"; +import { GlobalContext, showToast } from "@/context/Global"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import MkdSDK from "@/utils/MkdSDK"; +import { generateUUID } from "@/utils/utils"; +import { TbReplace } from "react-icons/tb"; +import Modal from "react-modal"; +import { FaMicrophoneAlt, FaSpinner, FaSquare } from "react-icons/fa"; +import { CgSpinner } from "react-icons/cg"; +import "regenerator-runtime/runtime"; +import SpeechRecognition, { + useSpeechRecognition, +} from "react-speech-recognition"; + +const customStyles = { + content: { + top: "50%", + left: "50%", + right: "auto", + bottom: "auto", + marginRight: "-50%", + transform: "translate(-50%, -50%)", + }, +}; + +const sdk = new MkdSDK(); + +const Transcribe = ({ + transcripts, + audioDesc, + saveData, + isFullView, + isRecording, + setIsRecording, + audioPlayerRef, + mediaRecorderRef, + audioChunksRef, + hasRecordedAudioFile, + setHasRecordedAudioFile, + transcribeLoading, + setTranscribeLoading, + transcribeResult, + setTranscribeResult, + audioFile, + setAudioFile, + setIsFullView, + transcribeBy, + setTranscribeBy, + isCreateSection, + setIsCreateSection, + sections, + setSections, + handleSaveTranscribe, + resultTextarea, + setResultTextarea, + selectedSection, + setSelectedSection, + activePdfPage, + setIsSpeechToText, + saveTranscribeLoading, + setSaveTranscribeLoading, + setIsBlocking, + isSaved +}) => { + const [hasSelectedAudioFile, setHasSelectedAudioFile] = useState(false); + const [isLangEnglish, setIsLangEnglish] = useState(true); + const { dispatch: globalDispatch } = useContext(GlobalContext); + const [sectionName, setSectionName] = useState(""); + const [sectionDescription, setSectionDescription] = useState(""); + const [isApending, setIsApending] = useState(true); + const [isReplacing, setIsReplacing] = useState(true); + const [transcribeType, setTranscribeType] = useState("append"); + const [description, setDescription] = useState(""); + const [transcribeTextBy, setTranscribeTextBy] = useState("default"); + const [isListening, setIsListening] = useState(false); + const [transcriptLoading, setTranscriptLoading] = useState(false); + const { transcript, browserSupportsSpeechRecognition, resetTranscript } = + useSpeechRecognition(); + let subtitle; + + async function handleFileInput(el) { + const fileObj = el.target.files[0]; + if (fileObj) { + const objectURL = URL.createObjectURL(fileObj); + audioPlayerRef.current.src = objectURL; + setHasSelectedAudioFile(true); + setAudioFile(fileObj); + } + } + + async function handleTranscribeBtn(type) { + try { + if (audioFile) { + setTranscribeLoading(true); + const result = isLangEnglish + ? await transcribeAudio(audioFile) + : await translateAudio(audioFile); + setTranscribeResult(result?.message); + type === "replace" + ? setResultTextarea(() => result?.message) + : setResultTextarea((prev) => + prev?.length ? `${prev}\n${result?.message}` : result?.message + ); + setTranscribeTextBy("default"); + setIsBlocking(resultTextarea?.length > 0 ? true : false); + } + } catch (error) { + showToast(globalDispatch, error, 1500, "error"); + } finally { + setHasRecordedAudioFile(false); + setHasSelectedAudioFile(false); + setTranscribeLoading(false); + } + } + + async function transcribeAudio(audioFile) { + try { + let formData = new FormData(); + formData.append("file", audioFile); + const transcriptRes = await sdk.gptTranscribe(formData); + return transcriptRes; + } catch (error) { + console.error(error); + } + } + + async function translateAudio(audioFile) { + let transcriptRes; + try { + let formData = new FormData(); + formData.append("file", audioFile); + transcriptRes = await sdk.gptTranslate(formData); + return transcriptRes; + } catch (error) { + console.error(error); + } + return transcriptRes; + } + + function copyToClipboard(text) { + navigator.clipboard.writeText(text); + showToast(globalDispatch, "Copied to clipboard"); + } + + const startRecording = async () => { + setIsRecording(true); + setTranscribeTextBy("audio"); + mediaRecorderRef.current = null; + audioChunksRef.current = []; + setAudioFile(null); + try { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + + mediaRecorderRef.current = new MediaRecorder(stream); + + mediaRecorderRef.current.ondataavailable = (event) => { + if (event.data.size > 0) { + audioChunksRef.current.push(event.data); + } + }; + + mediaRecorderRef.current.onstop = () => { + const audioBlob = new Blob(audioChunksRef.current, { + type: "audio/wav", + }); + const maxSizeBytes = 23 * 1024 * 1024; // 23 MB in bytes + if (audioBlob.size > maxSizeBytes) { + alert( + "Recording size exceeds the limit (23 MB). Please record a shorter audio." + ); + // You may want to handle this case differently, e.g., clear recording and prevent further actions + return; + } + + const audioUrl = URL.createObjectURL(audioBlob); + audioPlayerRef.current.src = audioUrl; + const audioFile = new File([audioBlob], "recorded_audio.wav", { + type: "audio/wav", + }); + setAudioFile(audioFile); + setHasRecordedAudioFile(true); + setIsApending(true); + setIsReplacing(true); + }; + + mediaRecorderRef.current.start(); + } catch (error) { + setIsRecording(false); + console.error("Error accessing microphone:", error); + showToast(globalDispatch, "Error accessing microphone", 1500, "error"); + } + }; + + const stopRecording = async () => { + if (mediaRecorderRef.current) { + mediaRecorderRef.current.stop(); + const tracks = mediaRecorderRef.current.stream.getTracks(); + tracks.forEach((track) => track.stop()); + mediaRecorderRef.current = null; + audioChunksRef.current = []; + await handleTranscribeBtn(audioFile); + setAudioFile(""); + setIsRecording(false); + } + }; + + useEffect(() => { + audioPlayerRef.current.src = audioDesc?.content; + + setResultTextarea(transcripts?.transcript || ""); + setSaveTranscribeLoading(false); + const section_desc = sections?.find( + (item) => item?.id === selectedSection + )?.description; + setDescription(section_desc || ""); + }, [transcripts, audioDesc, selectedSection]); + + useEffect(() => { + if (audioPlayerRef.current) { + audioPlayerRef.current.load(); + // audioPlayerRef.current.play(); + } + }, [audioPlayerRef?.current?.src]); + + useEffect(() => { + audioPlayerRef.current.src = audioDesc?.content; + setResultTextarea(transcripts?.transcript || ""); + setTranscribeTextBy("default"); + }, [transcribeBy === "page" ? activePdfPage : selectedSection]); + + useEffect(() => { + const transcript = !transcripts?.transcript ? "" : transcripts?.transcript; + if (transcript !== resultTextarea) { + setIsBlocking(resultTextarea?.length > 0 ? true : false); + } else { + setIsBlocking(false); + } + }, [resultTextarea]); + + const handleSaveSection = () => { + if (!sectionName?.length) { + return showToast(globalDispatch, "Section Name missing", 2000, "error"); + } + + const isExist = sections?.some( + (item) => item?.name?.toLowerCase() === sectionName?.toLowerCase() + ); + if (!isExist) { + const newsection = { + id: generateUUID(), + name: sectionName, + description: sectionDescription, + }; + setSections([...sections, newsection]); + saveData("sections", [...sections, newsection]); + setSelectedSection(newsection?.id); + } else { + showToast(globalDispatch, "Section Already Exist!", 2000, "error"); + } + + setSectionName(""); + setSectionDescription(""); + closeModal(); + }; + + const openModal = () => { + setIsCreateSection(true); + }; + + const handleEditDescription = () => { + if (selectedSection?.length) { + const selectedIndex = sections.findIndex((section) => { + return section && section.id === selectedSection; + }); + + const existArr = sections; + existArr[selectedIndex].description = description; + setSections([...existArr]); + saveData("sections", existArr); + } + }; + + const closeModal = () => { + setIsCreateSection(false); + setSectionName(""); + setSectionDescription(""); + }; + + if (!browserSupportsSpeechRecognition) { + return Browser doesn't support speech recognition.; + } + + const handleSpeechToText = () => { + setTranscriptLoading(true); + if (!isListening) { + resetTranscript(); + SpeechRecognition.startListening({ continuous: true, language: "en-IN" }); + setIsListening(true); + setTranscribeTextBy("speech"); + setIsSpeechToText(true); + setTimeout(() => { + setTranscriptLoading(false); + }, 1000); + } else { + setTimeout(() => { + SpeechRecognition.stopListening(); + setIsListening(false); + setTranscribeTextBy("default"); + setIsSpeechToText(false); + setTranscriptLoading(false); + setResultTextarea((prev) => + prev?.length ? `${prev} \n\n${transcript}` : transcript + ); + }, 1000); + } + }; + + return ( + <> + {isFullView ? ( +
    +
    +
    +
    +
    + + +
    + {transcribeBy === "section" ? ( +
    +
    + + +
    +
    + ) : null} +
    + {selectedSection?.length ? ( +
    + + +
    +
    + +
    +
    +
    +
    + ) : ( +
    +
    +
    +
    +
    + + +
    + {transcribeBy === "section" ? ( +
    +
    + + +
    +
    + +
    +
    + ) : null} +
    +
    +
    +
    +
    + {selectedSection?.length ? ( +
    + + +
    + +
    +
    + +
    +
    + {/*
    */} + + {/*
    */} +
    +
    +
    +
    + )} +
    + +
    +
    + Add a New Section +
    +
    +
    + + setSectionName(event.target.value)} + type="text" + className="mb-3.5 w-full rounded-md border border-[#C6C6C6] shadow-sm hover:bg-[#f4f4f4]" + /> +
    +
    + + + setSectionDescription(event.target.value) + } + type="text" + className="mb-3.5 w-full rounded-md border border-[#C6C6C6] shadow-sm hover:bg-[#f4f4f4]" + /> +
    + +
    + + +
    +
    +
    +
    +
    + + ); +}; + +export default Transcribe; diff --git a/src/components/PreWireframeTabs/UiComponent.tsx b/src/components/PreWireframeTabs/UiComponent.tsx new file mode 100644 index 0000000..7d59d79 --- /dev/null +++ b/src/components/PreWireframeTabs/UiComponent.tsx @@ -0,0 +1,21 @@ +import React from 'react' + +const UiComponent = () => { + return ( +
    +
    Create and Supercharge The Organization Of Your UI
    + +
    + + +
    +
    + + ) +} + +export default UiComponent \ No newline at end of file diff --git a/src/components/PreWireframeTabs/index.ts b/src/components/PreWireframeTabs/index.ts new file mode 100644 index 0000000..56a86e7 --- /dev/null +++ b/src/components/PreWireframeTabs/index.ts @@ -0,0 +1,8 @@ +import { lazy } from "react"; + +export const Docs = lazy(() => import("./Docs")); +export const Transcribe = lazy(() => import("./Transcribe")); +export const DbSchema = lazy(() => import("./DbSchema")); +export const ApiSection = lazy(() => import("./ApiSection")); +export const UiComponent = lazy(() => import("./UiComponent")); +export const TextareaTab = lazy(() => import("./TextareaTab")); diff --git a/src/components/Preview.tsx b/src/components/Preview.tsx deleted file mode 100644 index 60ac586..0000000 --- a/src/components/Preview.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { TransformedImage } from '../types'; - -interface PreviewProps { - transformedImage: TransformedImage; -} - -export function Preview({ transformedImage }: PreviewProps) { - return ( -
    -

    Your Transformation

    -
    -
    -

    Original

    - Original -
    -
    -

    - As {transformedImage.character.name} -

    - Transformed -
    -
    -
    - -
    -
    - ); -} \ No newline at end of file diff --git a/src/components/ProgressBar/ProgressBar.tsx b/src/components/ProgressBar/ProgressBar.tsx new file mode 100644 index 0000000..ecd25ce --- /dev/null +++ b/src/components/ProgressBar/ProgressBar.tsx @@ -0,0 +1,13 @@ +import React from 'react' + +const ProgressBar = ({percentage, color, backgroundColor}) => { + return ( +
    +
    +
    {percentage}
    +
    +
    + ) +} + +export default ProgressBar \ No newline at end of file diff --git a/src/components/ProgressBar/index.ts b/src/components/ProgressBar/index.ts new file mode 100644 index 0000000..da66d62 --- /dev/null +++ b/src/components/ProgressBar/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const ProgressBar = lazy(() => import("./ProgressBar")); + + \ No newline at end of file diff --git a/src/components/PublicHeader/PublicHeader.tsx b/src/components/PublicHeader/PublicHeader.tsx new file mode 100644 index 0000000..bc74d50 --- /dev/null +++ b/src/components/PublicHeader/PublicHeader.tsx @@ -0,0 +1,27 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router"; +import { AuthContext } from "@/context/Auth"; +import Navbar from "@/components/ExternalUI/Navbar"; +import { Link } from "react-router-dom"; + +export const PublicHeader = () => { + const { state, dispatch } = React.useContext(AuthContext); + const [isOpen, setIsOpen] = useState(false); + const navigate = useNavigate(); + + return ( +
    + + {/* */} +
    + ); +}; + +export default PublicHeader; diff --git a/src/components/PublicHeader/index.ts b/src/components/PublicHeader/index.ts new file mode 100644 index 0000000..5f2b098 --- /dev/null +++ b/src/components/PublicHeader/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const PublicHeader = lazy(() => import("./PublicHeader")); + + \ No newline at end of file diff --git a/src/components/PublicWrapper/PublicWrapper.tsx b/src/components/PublicWrapper/PublicWrapper.tsx new file mode 100644 index 0000000..a2e2c8f --- /dev/null +++ b/src/components/PublicWrapper/PublicWrapper.tsx @@ -0,0 +1,26 @@ +import React, { Suspense, memo } from "react"; +import { PublicHeader } from "@/components/PublicHeader"; +import { Spinner } from "@/assets/svgs"; +// import { ProgressBar } from "@/components/ProgressBar"; + +const PublicWrapper = ({ children }) => { + return ( +
    + +
    + + +
    + } + > + {children} + +
    + {/*
    */} +
    + ); +}; + +export default memo(PublicWrapper); diff --git a/src/components/PublicWrapper/index.ts b/src/components/PublicWrapper/index.ts new file mode 100644 index 0000000..628afda --- /dev/null +++ b/src/components/PublicWrapper/index.ts @@ -0,0 +1 @@ +export { default as PublicWrapper } from "./PublicWrapper"; diff --git a/src/components/QrCodeGenerator/QrCodeGenerator.tsx b/src/components/QrCodeGenerator/QrCodeGenerator.tsx new file mode 100644 index 0000000..948d5cb --- /dev/null +++ b/src/components/QrCodeGenerator/QrCodeGenerator.tsx @@ -0,0 +1,65 @@ +import React from "react"; +import QRCode from "qrcode"; + +const QrCodeGenerator = ({ setResult }) => { + const [textToGenerate, setTextToGenerate] = React.useState(""); + const [generatedQrcodeImageUrl, setGeneratedQrcodeImageUrl] = + React.useState(); + + async function generateQrCode(text) { + try { + const response = await QRCode.toDataURL(text); + setGeneratedQrcodeImageUrl(response); + if (setResult) { + setResult(response); + } + } catch (error) { + console.error(error); + } + } + + return ( + <> +
    +
    +
    + + setTextToGenerate(e.target.value)} + className="focus:shadow-outline mb-3 w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none" + /> +
    +
    + + {generatedQrcodeImageUrl && ( + + + + )} +
    +
    + {generatedQrcodeImageUrl && ( + Qr Code + )} +
    + + ); +}; + +export default QrCodeGenerator; diff --git a/src/components/QrCodeGenerator/index.ts b/src/components/QrCodeGenerator/index.ts new file mode 100644 index 0000000..3d78929 --- /dev/null +++ b/src/components/QrCodeGenerator/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const QrCodeGenerator = lazy(() => import("./QrCodeGenerator")); + + \ No newline at end of file diff --git a/src/components/QrCodeReader/QrCodeReader.tsx b/src/components/QrCodeReader/QrCodeReader.tsx new file mode 100644 index 0000000..25c17d1 --- /dev/null +++ b/src/components/QrCodeReader/QrCodeReader.tsx @@ -0,0 +1,53 @@ +import React, { useRef } from "react"; +import QrScanner from "qr-scanner"; + +const QrCodeReader = ({ setResult }) => { + const [scannedQrFile, setScannedQrFile] = React.useState(""); + const fileRef = useRef(null); + + function handleScanFileBtn() { + fileRef.current.click(); + } + + async function handleChangeScanFileBtn(e) { + const file = e.target.files[0]; + try { + const result = await QrScanner.scanImage(file, { + returnDetailedScanResult: true, + }); + await setScannedQrFile(result.data); + if (setResult) { + setResult(result.data); + } + } catch (err) { + setScannedQrFile(err); + } + } + + return ( +
    +
    +
    + +
    +

    Scanned Code Result: {scannedQrFile && scannedQrFile}

    +
    +
    + ); +}; + +export default QrCodeReader; diff --git a/src/components/QrCodeReader/index.ts b/src/components/QrCodeReader/index.ts new file mode 100644 index 0000000..0a13fc6 --- /dev/null +++ b/src/components/QrCodeReader/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const QrCodeReader = lazy(() => import("./QrCodeReader")); + + \ No newline at end of file diff --git a/src/components/RatingStar/RatingStar.tsx b/src/components/RatingStar/RatingStar.tsx new file mode 100644 index 0000000..d436312 --- /dev/null +++ b/src/components/RatingStar/RatingStar.tsx @@ -0,0 +1,96 @@ +import { StarIcon } from "@heroicons/react/24/solid"; +import React, { useEffect, useState } from "react"; + +const RatingStar = ({ rate = 0, onSetRate }) => { + const [rateValue, setRateValue] = useState(0); + const [hoveredIndex, setHoveredIndex] = useState(0); + + const handleClick = (number) => { + if (rateValue === number) { + onSetRate(0); + if (setRateValue) { + setRateValue(0); + } + } else { + onSetRate(number); + if (setRateValue) { + setRateValue(number); + } + } + }; + useEffect(() => { + setRateValue(rate); + }, [rate]); + + const handleMouseOver = (e) => { + if (e.target.id) { + if (e.target.id.includes("path_")) { + setHoveredIndex(e.target.id.replace("path_", "").trim()); + } else { + setHoveredIndex(e.target.id); + } + } + }; + + const handleMouseOut = () => { + setHoveredIndex(0); + }; + + return ( + <> +
    + + = 1 ? "text-yellow-200" : "" + } ${rateValue >= 1 ? "text-yellow-400 " : "text-gray-500"}`} + onClick={() => handleClick(1)} + /> + + + = 2 ? "text-yellow-200" : "" + } ${rateValue >= 2 ? "text-yellow-400 " : "text-gray-500"}`} + onClick={() => handleClick(2)} + /> + + + = 3 ? "text-yellow-200" : "" + } ${rateValue >= 3 ? "text-yellow-400 " : "text-gray-500"}`} + onClick={() => handleClick(3)} + /> + + + = 4 ? "text-yellow-200" : "" + } ${rateValue >= 4 ? "text-yellow-400 " : "text-gray-500"}`} + onClick={() => handleClick(4)} + /> + + + = 5 ? "text-yellow-200" : "" + } ${rateValue === 5 ? "text-yellow-400 " : "text-gray-500"}`} + onClick={() => handleClick(5)} + /> + +
    + + ); +}; + +export default RatingStar; diff --git a/src/components/RatingStar/index.ts b/src/components/RatingStar/index.ts new file mode 100644 index 0000000..0c467ed --- /dev/null +++ b/src/components/RatingStar/index.ts @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + +export const RatingStar = lazy(() => import("./RatingStar")); + + \ No newline at end of file diff --git a/src/components/RouteChangeModal/RouteChange.tsx b/src/components/RouteChangeModal/RouteChange.tsx new file mode 100644 index 0000000..33292ab --- /dev/null +++ b/src/components/RouteChangeModal/RouteChange.tsx @@ -0,0 +1,46 @@ +import { Fragment } from "react"; +import { LazyLoad } from "@/components/LazyLoad"; +import { Link } from "react-router-dom"; + +export type OptionType = { + name: string; + route: string; +}; + +interface RouteChangeProps { + onClose: () => void; + options: Array; +} + +export const RouteChange = ({ + onClose, + options = [ + { + name: "", + route: "", + }, + ], +}: RouteChangeProps) => { + return ( + + +
    + {options?.map((option, optionKey) => { + return ( + + {option?.name} + + ); + })} +
    +
    +
    + ); +}; + +export default RouteChange; diff --git a/src/components/RouteChangeModal/RouteChangeModal.tsx b/src/components/RouteChangeModal/RouteChangeModal.tsx new file mode 100644 index 0000000..cca6347 --- /dev/null +++ b/src/components/RouteChangeModal/RouteChangeModal.tsx @@ -0,0 +1,50 @@ +import { LazyLoad } from "@/components/LazyLoad"; +import { Modal, ModalClassType } from "@/components/Modal"; +import { OptionType, RouteChange } from "./index"; + +interface RouteChangeModalProps { + isOpen: boolean; + title: string; + onClose: () => void; + options: Array; + modalClasses?: ModalClassType; + customMessage?: string, +} + +export const RouteChangeModal = ({ + isOpen = false, + title = "change route", + onClose, + options = [ + { + name: "", + route: "", + }, + ], + modalClasses = { + modalDialog: + "max-h-[90%] min-h-[12rem] overflow-y-auto !w-full md:!w-[29.0625rem]", + modal: "h-full", + }, +}: RouteChangeModalProps) => { + + return ( + + + {isOpen && ( + + + + )} + + + ); +}; + +export default RouteChangeModal; diff --git a/src/components/RouteChangeModal/index.ts b/src/components/RouteChangeModal/index.ts new file mode 100644 index 0000000..d75eefc --- /dev/null +++ b/src/components/RouteChangeModal/index.ts @@ -0,0 +1,5 @@ +import { lazy } from "react"; + +export const RouteChange = lazy(() => import("./RouteChange")); +export const RouteChangeModal = lazy(() => import("./RouteChangeModal")); +export { type OptionType } from "./RouteChange"; diff --git a/src/components/ScaleModalOverlay/ScaleModalOverlay.tsx b/src/components/ScaleModalOverlay/ScaleModalOverlay.tsx new file mode 100644 index 0000000..43e3a2c --- /dev/null +++ b/src/components/ScaleModalOverlay/ScaleModalOverlay.tsx @@ -0,0 +1,72 @@ +import React, { useState } from "react"; +import { CloseIcon } from "@/assets/svgs"; + +const ScaleModalOverlay = ({ + children, + title, + isOpen = false, + modalCloseClick, + modalHeader, + classes, +}) => { + const [offsetTop, setOffsetTop] = useState(0); + + const onClose = (e) => { + if (e.target.id === "overlay") { + modalCloseClick(); + } + }; + + return ( +
    +
    +
    + {modalHeader && ( +
    +
    +
    + {title} +
    +
    +
    + +
    +
    + )} + +
    + {children} +
    +
    +
    +
    + ); +}; + +export default ScaleModalOverlay; diff --git a/src/components/ScaleModalOverlay/index.ts b/src/components/ScaleModalOverlay/index.ts new file mode 100644 index 0000000..1f303db --- /dev/null +++ b/src/components/ScaleModalOverlay/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const ScaleModalOverlay = lazy(() => import("./ScaleModalOverlay")); diff --git a/src/components/SearchableDropdown/SearchableDropdown.module.css b/src/components/SearchableDropdown/SearchableDropdown.module.css new file mode 100644 index 0000000..d34a311 --- /dev/null +++ b/src/components/SearchableDropdown/SearchableDropdown.module.css @@ -0,0 +1,32 @@ +.button { + position: relative; + /* border: none; */ + color: #ffffff; + text-align: center; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + text-decoration: none; + overflow: hidden; + cursor: pointer; + /* background-color: #7B1113; */ +} +.button:after { + content: ""; + background-color: #7b1113; + /* background: #4f46e5; */ + display: block; + position: absolute; + padding-top: 300%; + padding-left: 350%; + margin-left: -20px !important; + margin-top: -120%; + opacity: 0; + transition: all 0.8s; +} + +.button:active:after { + padding: 0; + margin: 0; + opacity: 1; + transition: 0s; +} diff --git a/src/components/SearchableDropdown/SearchableDropdown.tsx b/src/components/SearchableDropdown/SearchableDropdown.tsx new file mode 100644 index 0000000..3ec06a5 --- /dev/null +++ b/src/components/SearchableDropdown/SearchableDropdown.tsx @@ -0,0 +1,705 @@ +import React, { + memo, + useCallback, + useEffect, + useMemo, + useState, +} from "react"; +import { v4 as uuidv4 } from "uuid"; +import { ChevronUpIcon } from "@/assets/svgs"; +import { Skeleton as SkeletonLoader } from "@/components/Skeleton"; +import { StringCaser } from "@/utils/utils" +import { useContexts } from "@/hooks/useContexts"; + +const getMaxHeight = (maxHeight: any) => { + if (maxHeight) { + return `max-h-[${maxHeight}]`; + } + return `max-h-[18.75rem]`; +}; + + +interface SearchableDropdownProps { + onSelect?: (option: any, clear?: boolean) => void; + showBorder?: boolean; + display: string | string[] | { and: string[]; or: string[] }; + value?: string | number; + uniqueKey: string; + selector?: any; + disabled?: boolean; + placeholder?: string; + label?: string; + maxHeight?: string; + height?: string; + selectedOptions?: any[]; + table?: string; + errors?: any; + name?: string; + className?: string; + join?: string[]; + filter?: string[]; + mode?: string; + useExternalData?: boolean; + externalDataLoading?: boolean; + externalDataOptions?: any[]; + onReady?: (data: any[]) => void; + refreshRef?: React.Ref; + clearRef?: React.Ref; + showSearchIcon?: boolean; + required?: boolean; + dataRetrievalState?: string; + displaySeparator?: string; + customOptions?: { + show: boolean; + action?: () => void; + icon?: JSX.Element; + children?: string; + }[]; + onPopoverStateChange?: (show: boolean) => void; + popoverShown?: boolean; +} + +const SearchableDropdown = ({ + onSelect, + showBorder = true, + display = "display", + value, + uniqueKey, + selector = null, + disabled = false, + placeholder = "- search -", + label = "Select", + maxHeight = "18.75rem", + height = "fit-content", + selectedOptions = [], + table = "", + errors, + name, + className = "w-[23rem]", + join = [], + filter = [], + mode = "static", + useExternalData = false, + externalDataLoading = false, + externalDataOptions = [], + onReady, + refreshRef = null, + clearRef = null, + showSearchIcon = false, + required = false, + dataRetrievalState, + displaySeparator = "", + customOptions = [], + onPopoverStateChange, + popoverShown, +}: SearchableDropdownProps) => { + // Refs + const uniqueId = uuidv4({ namespace: "SearchableDropdown" }); + const uniqueClassName = btoa(uniqueId); + + // Context + const { globalState, getMany: getList } = useContexts(); + const dropdownModel = globalState[dataRetrievalState ?? table]; + + + // State + const [options, setOptions] = useState([]); + const [showLists, setShowLists] = useState(false); + const [searchValue, setSearchValue] = useState(""); + const [selectedOption, setSelectedOption] = useState(null); + const [localOptions, setLocalOptions] = useState([]); + + // Hooks + const memoizedFilter = useMemo(() => filter, [filter]); + const memoizedExternalDataOptions = useMemo( + () => JSON.stringify(externalDataOptions), + [externalDataOptions] + ); + + const getDropdowList = async () => { + const result = await getList( + table, + { + ...{ ...(memoizedFilter?.length ? { filter: memoizedFilter } : null) }, + ...{ ...(join && join?.length ? { join } : null) }, + }, + dataRetrievalState && dataRetrievalState + ); + if (!result.error) { + if (table === "user") { + const usersWithFullName = result?.data?.map((item: { first_name: any; last_name: any; }) => { + if (item?.first_name || item?.last_name) { + return { + ...item, + full_name: StringCaser(`${item.first_name} ${item.last_name}`, { + casetype: "capitalize", + separator: " ", + }), + }; + } else { + return item; + } + }); + setOptions(() => [...usersWithFullName]); + setLocalOptions(() => [...usersWithFullName]); + } else { + setOptions(() => [...result?.data]); + setLocalOptions(() => [...result?.data]); + } + if (value) { + const selectedOption = result?.data.find( + (option: { [x: string]: string | number; }) => option[uniqueKey] == value + ); + // console.log("value >>", value); + // console.log("result?.data >>", result?.data); + // console.log("selectedOption >>", selectedOption); + if (selectedOption) { + setSelectedOption(() => selectedOption); + } + } + + if (onReady) { + onReady(result?.data); + } + } + }; + + const displayName = (option: never, display: string | number | any[] | { and: string[]; or: string[]; }, where?: string) => { + if (typeof display === "string") { + return String(option[display]); + } + if (typeof display === "object") { + if (Array.isArray(display)) { + // handle array case + const invalid = display.some((item) => typeof item !== "string"); + if (invalid) { + return String(option[Object.keys(option)[0]]); + } + const result = display.map((key) => option[key]); + + return String( + result.length + ? result.join(` ${displaySeparator} `) + : result.join(" ") + ); + } else { + // handle object case + + const isNotOneOrTwoFields = ![1, 2].includes( + Object.keys(display).length + ); + if (isNotOneOrTwoFields) { + return String(option[Object.keys(option)[0]]); + } + + const isNotOnlyAndOr = Object.keys(display).some( + (key) => !["and", "or"].includes(key) + ); + if (isNotOnlyAndOr) { + return String(option[Object.keys(option)[0]]); + } + + const andField = display["and"]; + const orField = display["or"]; + + if (andField && orField) { + if (typeof andField === "string" && typeof orField === "string") { + const andValue = option[andField]; + const orValue = option[orField]; + + return String( + andValue || orValue || option[Object.keys(option)[0]] + ); + } + if (Array.isArray(andField) && Array.isArray(orField)) { + const someAndValuesNotExist = andField.some((key) => !option[key]); + if (someAndValuesNotExist) { + const orValue = orField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + orValue.length + ? orValue.length + ? orValue.join(` ${displaySeparator} `) + : orValue.join(" ") + : option[Object.keys(option)[0]] + ); + } + + const andValue = andField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + andValue.length + ? andValue.join(` ${displaySeparator} `) + : andValue.join(" ") + ); + } + + if (Array.isArray(andField) && typeof orField === "string") { + const someAndValuesNotExist = andField.some((key) => !option[key]); + if (someAndValuesNotExist) { + const orValue = option[orField]; + + return String(orValue || option[Object.keys(option)[0]]); + } + const andValue = andField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + andValue.length + ? andValue.join(` ${displaySeparator} `) + : andValue.join(" ") + ); + } + + if (Array.isArray(orField) && typeof andField === "string") { + const andValue = option[andField]; + if (andValue) { + return String(andValue); + } + + const orValue = orField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + orValue.length + ? orValue.length + ? orValue.join(` ${displaySeparator} `) + : orValue.join(" ") + : option[Object.keys(option)[0]] + ); + } + } else if (andField && !orField) { + if (typeof andField === "string") { + const andValue = option[andField]; + + return String(andValue || option[Object.keys(option)[0]]); + } + if (Array.isArray(andField)) { + const andValue = andField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + andValue.length + ? andValue.length + ? andValue.join(` ${displaySeparator} `) + : andValue.join(" ") + : option[Object.keys(option)[0]] + ); + } + } else if (!andField && orField) { + if (typeof orField === "string") { + const orValue = option[orField]; + + return String(orValue || option[Object.keys(option)[0]]); + } + + if (Array.isArray(orField)) { + const orValue = orField + .map((key) => { + if (option[key]) { + return option[key]; + } + }) + .filter(Boolean); + + return String( + orValue.length + ? orValue.length + ? orValue.join(` ${displaySeparator} `) + : orValue.join(" ") + : option[Object.keys(option)[0]] + ); + } + } + } + } + }; + const selectOption = (option: React.SetStateAction, clear = false, externalUpdate = true) => { + // setSelectedOption(option[display]) + if (externalUpdate && !onSelect) { + return; + } + if (clear) { + setSelectedOption(null); + onSelect&& onSelect(null, true); + return setShowLists(false); + } + setSelectedOption(option); + if (externalUpdate) { + onSelect&& onSelect(option); + } + if (searchValue) { + setSearchValue(""); + } + if (options.length && options?.length > localOptions) { + setLocalOptions(options); + } + if (showLists) { + setShowLists(false); + } + // setShowLists((prev) => !prev); + }; + + const isChecked = useCallback( + (option: { [x: string]: any; }) => { + if (uniqueKey) { + const exist = selectedOptions.find( + (opt) => opt[uniqueKey] === option[uniqueKey] + ); + if (exist) { + return true; + } else { + return false; + } + } + }, + [options, localOptions, selectedOptions] + ); + const getDisplayValue = useCallback(() => { + if (showLists || searchValue) { + return searchValue; + } else if (selectedOption) { + return displayName(selectedOption, display, "selectedOption in value"); + } else if (value && options && options?.length) { + const valueOption = options?.find( + (opt) => opt[uniqueKey] === Number(value) + ); + if (valueOption) { + return displayName(valueOption, display, "options in value"); + } else { + return ""; + } + } else { + return ""; + } + }, [showLists, value, searchValue, selectOption, options]); + + const onSetSearchValue = useCallback( + (value: React.SetStateAction) => { + // console.log("onSetSearchValue") + setSearchValue(value); + if (value) { + const matches = options.filter((option) => + displayName(option, display, "search") + .toLowerCase() + .includes(value.toLowerCase()) + ); + setLocalOptions(matches); + } else { + setLocalOptions(options); + } + // setLedgerSelected(false) + }, + [searchValue] + ); + + useEffect(() => { + const abortController = new AbortController(); + + const handleClick = (e: MouseEvent) => { + const target = e.target as HTMLElement; + if (!target.closest(`.${uniqueClassName}`)) { + setShowLists((prev) => { + if (prev) { + return !prev; + } + return prev; + }); + } + }; + + window.addEventListener("click", handleClick, { signal: abortController.signal }); + + return () => abortController.abort(); + }, []); + + + useEffect(() => { + // console.log("memoizedExternalDataOptions >>", memoizedExternalDataOptions); + if (!useExternalData && !options?.length) { + getDropdowList(); + } + }, [useExternalData]); + + useEffect(() => { + if (useExternalData) { + setOptions(() => [...externalDataOptions]); + setLocalOptions(() => [...externalDataOptions]); + } + }, [useExternalData, memoizedExternalDataOptions]); + + // useEffect(() => { + // if (["reactive"].includes(mode)) { + // console.log("options?.length >>", options?.length); + // // getDropdowList(); + // } + // }, [memoizedFilter]); + + useEffect(() => { + if (onPopoverStateChange) { + if (!popoverShown && showLists) { + onPopoverStateChange(true); + } + } + }, [popoverShown, showLists]); + // console.log("selectedOption >>", selectedOption); + return ( + <> + + +
    + {label && ( + + )} + {/*
    */} + {externalDataLoading || dropdownModel?.loading ? ( + + ) : ( + <> +
    + {showSearchIcon && !disabled && ( +
    + +
    + )} +
    + { + if (!showLists) { + setShowLists(true); + } + }} + // onBlur={() => showLists && setShowLists(false)} + onChange={(e) => + onSetSearchValue(e.target.value.toLowerCase()) + } + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + } + }} + /> +
    + {!disabled && ( +
    + + +
    + )} +
    + +
    +
    +
    selectOption(null, true)} + > + None +
    + {customOptions.length && + customOptions.find((customOption) => customOption?.show) + ? customOptions?.map((option, optionIndex) => { + if (option?.show) { + return ( +
    option?.action && option?.action()} + > + {option?.icon ? option.icon : null} + {option?.children ? option.children : null} +
    + ); + } + }) + : null} + {localOptions.length + ? localOptions?.map((option, index) => { + if (option?.searchableType === "section") { + return ( +
    + {option?.display} +
    + ); + } + return ( + + ); + }) + : null} +
    +
    + {/*
    */} + + {errors && name && errors?.[name!] && ( +

    + {StringCaser(errors?.[name!]?.message, { + casetype: "capitalize", + separator: " ", + })} +

    + )} + + )} +
    + + ); +}; + +export default memo(SearchableDropdown); diff --git a/src/components/SearchableDropdown/index.ts b/src/components/SearchableDropdown/index.ts new file mode 100644 index 0000000..00745a1 --- /dev/null +++ b/src/components/SearchableDropdown/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const SearchableDropdown = lazy(() => import("./SearchableDropdown")); diff --git a/src/components/SessionExpiredModal/SessionExpiredModal.tsx b/src/components/SessionExpiredModal/SessionExpiredModal.tsx new file mode 100644 index 0000000..2b0d90f --- /dev/null +++ b/src/components/SessionExpiredModal/SessionExpiredModal.tsx @@ -0,0 +1,101 @@ +import { Fragment, useEffect } from "react"; +import { Dialog, Transition } from "@headlessui/react"; +import { useLocation, useNavigate } from "react-router"; +import { useContexts } from "@/hooks/useContexts"; +import { updatedRolesFn } from "@/utils/utils"; +import { RoleEnum } from "@/utils/Enums"; + +let modalTimeout: string | number | NodeJS.Timeout | undefined; + +export default function SessionExpiredModal() { + const { authState: state, authDispatch: dispatch } = useContexts(); + + const location = useLocation(); + const { pathname } = location; + const navigate = useNavigate(); + + const role = state?.role as RoleEnum; + const sessionExpired = state?.sessionExpired; + + const logout = () => { + dispatch({ type: "SESSION_EXPIRED", payload: false }); + dispatch({ type: "LOGOUT" }); + if (role) { + navigate( + `${updatedRolesFn(role, location)}/login?redirect_uri=${pathname}` + ); + } else { + navigate(`/login?redirect_uri=${pathname}`); + } + clearTimeout(modalTimeout); + }; + + useEffect(() => { + if (sessionExpired) { + modalTimeout = setTimeout(() => { + logout(); + }, 4000); + } + }, [sessionExpired]); + + if (!sessionExpired) return null; + + return ( +
    + + {}}> + +
    + + +
    +
    + + + + Session Expired + +
    +

    + Your current login session has expired. Redirecting to + login page shortly +

    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + ); +} diff --git a/src/components/SessionExpiredModal/index.ts b/src/components/SessionExpiredModal/index.ts new file mode 100644 index 0000000..02cc877 --- /dev/null +++ b/src/components/SessionExpiredModal/index.ts @@ -0,0 +1,4 @@ + + export { default as SessionExpiredModal } from "./SessionExpiredModal"; + + \ No newline at end of file diff --git a/src/components/Skeleton/Skeleton.tsx b/src/components/Skeleton/Skeleton.tsx new file mode 100644 index 0000000..49aa8b9 --- /dev/null +++ b/src/components/Skeleton/Skeleton.tsx @@ -0,0 +1,40 @@ +import Skeleton from 'react-loading-skeleton'; + +interface SkeletonLoaderProps { + className?: string; + count?: number; + counts?: number[]; + circle?: boolean; +} + +const SkeletonLoader = ({ + className = '', + count = 5, + counts = [2, 1, 3, 1, 1], + circle = false, +}: SkeletonLoaderProps) => { + return ( +
    + {/* */} + {Array.from({ length: count }).map((_, index) => ( + 1 + ? 25 + : index + 1 === count + ? 25 + : 80 + } + circle={circle} + style={{ marginBottom: '0.6rem' }} + /> + ))} +
    + ); +}; + +export default SkeletonLoader; \ No newline at end of file diff --git a/src/components/Skeleton/index.ts b/src/components/Skeleton/index.ts new file mode 100644 index 0000000..c9c15dd --- /dev/null +++ b/src/components/Skeleton/index.ts @@ -0,0 +1 @@ +export { default as Skeleton } from "./Skeleton"; \ No newline at end of file diff --git a/src/components/SnackBar/SnackBar.tsx b/src/components/SnackBar/SnackBar.tsx new file mode 100644 index 0000000..d632272 --- /dev/null +++ b/src/components/SnackBar/SnackBar.tsx @@ -0,0 +1,133 @@ +import { useContexts } from "@/hooks/useContexts"; + +const SnackBar = () => { + const { + globalState, + globalDispatch: dispatch, + } = useContexts(); + + const globalMessage = globalState?.globalMessage; + const toastStatus = globalState?.toastStatus; + const show = globalMessage?.length > 0; + + return show ? ( + + ) : null; +}; + +export default SnackBar; diff --git a/src/components/SnackBar/index.ts b/src/components/SnackBar/index.ts new file mode 100644 index 0000000..576e417 --- /dev/null +++ b/src/components/SnackBar/index.ts @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const SnackBar = lazy(() => import("./SnackBar")); diff --git a/src/components/TopBarSticky/TopBarSticky.tsx b/src/components/TopBarSticky/TopBarSticky.tsx new file mode 100644 index 0000000..c9c5c86 --- /dev/null +++ b/src/components/TopBarSticky/TopBarSticky.tsx @@ -0,0 +1,149 @@ +import BackButton from 'Components/BackButton'; +import { ModalSidebar } from 'Components/ModalSidebar'; +import { Notifications } from 'Components/Notifications'; +import { AuthContext } from 'Context/Auth'; +import { GlobalContext } from 'Context/Global'; +import React, { useEffect, useState } from 'react' +import { Link, useLocation } from "react-router-dom" + +const TopBarSticky = () => { + const [currentPath, setCurrentPath] = useState(""); + const { state, dispatch } = React.useContext(AuthContext); + const { state: globalState } = React.useContext(GlobalContext); + const { isOpen, showBackButton } = globalState; + const [showSidebar, setShowSidebar] = useState(false); + const location = useLocation(); + + useEffect(() => { + const pathArr = location.pathname.split("/"); + if (pathArr[1] !== "user" && pathArr[1] !== "admin") { + setCurrentPath(pathArr[1]); + } else { + setCurrentPath(pathArr[2]); + } + }, [location]); + + return state?.isAuthenticated && ( + <> +
    +
    + {showBackButton && } +

    {currentPath}

    +
    +
    + {/* Notification Icon */} +
    setShowSidebar(true)}> + + + + +
    + {/* Profile image and dropdown */} +
    + +
      +
    • + + + + + + + + + + Account + +
    • +
    • + + dispatch({ + type: "LOGOUT", + }) + } + > + + + + + + Logout + +
    • +
    +
    +
    +
    + setShowSidebar(false)} + > + setShowSidebar(false)} /> + + + ) +} + +export default TopBarSticky \ No newline at end of file diff --git a/src/components/TopBarSticky/index.ts b/src/components/TopBarSticky/index.ts new file mode 100644 index 0000000..0c6ab61 --- /dev/null +++ b/src/components/TopBarSticky/index.ts @@ -0,0 +1 @@ +export { default as TopBarSticky } from "./TopBarSticky" \ No newline at end of file diff --git a/src/components/TopHeader/TopHeader.tsx b/src/components/TopHeader/TopHeader.tsx new file mode 100644 index 0000000..6729975 --- /dev/null +++ b/src/components/TopHeader/TopHeader.tsx @@ -0,0 +1,139 @@ +import React, { useEffect, useState } from "react"; +import { GlobalContext } from "@/context/Global"; +import { Link, useLocation } from "react-router-dom"; +import { BackButton } from "@/components/BackButton"; +import { AuthContext } from "@/context/Auth"; +import { StringCaser } from "@/utils/utils"; +import { useProfile } from "@/hooks/useProfile"; + +const TopHeader = () => { + const { state: globalState, dispatch: globalDispatch } = + React.useContext(GlobalContext); + const { state, dispatch } = React.useContext(AuthContext); + const [currentPath, setCurrentPath] = useState(""); + const { isOpen, showBackButton } = globalState; + const location = useLocation(); + const {profile} = useProfile(); + + let toggleOpen = (open) => { + dispatch({ + type: "OPEN_SIDEBAR", + payload: { isOpen: open }, + }); + }; + + useEffect(() => { + const pathArr = location.pathname.split("/"); + if (pathArr[1] !== "user" && pathArr[1] !== "admin") { + setCurrentPath(pathArr[1]); + } else { + setCurrentPath(pathArr[2]); + } + }, [location]); + + return ( +
    +
    + {showBackButton && } +

    + {currentPath === "generate-ui" + ? "Generate UI" + : StringCaser(currentPath, { + casetype: "capitalize", + separator: " ", + })} +

    +
    +
    +
    + +
      +
    • + + + + + + + + + + Account + +
    • +
    • + + dispatch({ + type: "LOGOUT", + }) + } + > + + + + + + Logout + +
    • +
    +
    +
    +
    + ); +}; + +export default TopHeader; diff --git a/src/components/TopHeader/index.ts b/src/components/TopHeader/index.ts new file mode 100644 index 0000000..6f3edc1 --- /dev/null +++ b/src/components/TopHeader/index.ts @@ -0,0 +1 @@ +export { default as TopHeader } from "./TopHeader"; diff --git a/src/components/builder/AndroidBuilder.tsx b/src/components/builder/AndroidBuilder.tsx new file mode 100644 index 0000000..e4e9810 --- /dev/null +++ b/src/components/builder/AndroidBuilder.tsx @@ -0,0 +1,701 @@ +import JSZip from "jszip"; +import { saveAs } from "file-saver"; +import SettingGradle from "./flatfile/SettingGradle"; +import Gradlewbat from "./flatfile/Gradlewbat"; +import GradleProperties from "./flatfile/GradleProperties"; +import BuildGradle from "./flatfile/BuildGradle"; +import BuildGradleApp from "./flatfile/BuildGradleApp"; +import GitIgnoreAndroid from "./flatfile/GitIgnoreAndroid"; +import GitIgnoreAndroidApp from "./flatfile/GitIgnoreAndroidApp"; +import ProguardRulesPro from "./flatfile/ProguardRulesPro"; +import TranslatorManifestAndroid from "./translator/TranslatorManifestAndroid"; +import AttrsColors from "./flatfile/AttrsColors"; +import AttrsDimens from "./flatfile/AttrsDimens"; +import AttrsStrings from "./flatfile/AttrsStrings"; +import AttrsMenuDrawer from "./flatfile/AttrsMenuDrawer"; +import TranslatorAppAndroid from "./translator/TranslatorAppAndroid"; +import TranslatorMainActivityAndroid from "./translator/TranslatorMainActivityAndroid"; +import TranslatorLocalAppPreferenceAndroid from "./translator/TranslatorLocalAppPreferenceAndroid"; +import TranslatorRemoteDataSourceAndroid from "./translator/TranslatorRemoteDataSourceAndroid"; +import TranslatorModulesAndroid from "./translator/TranslatorModulesAndroid"; +import TranslatorApiServiceAndroid from "./translator/TranslatorApiServiceAndroid"; +import ExtensionCommonAndroid from "./flatfile/ExtensionCommonAndroid"; +import TranslatorConstantAndroid from "./translator/TranslatorConstantAndroid"; +import TranslatorEnumAndroid from "./translator/TranslatorEnumAndroid"; +import FragmentDelegate from "./flatfile/FragmentDelegate"; +import StringExtensionAndroid from "./flatfile/StringExtensionAndroid"; +import ExtensionViewAndroid from "./flatfile/ExtensionViewAndroid"; +import MyFirebasePushNotifications from "./flatfile/MyFirebasePushNotifications"; +import TranslatorRepositoryAndroid from "./translator/TranslatorRepositoryAndroid"; +import TranslatorFragmentAndroid from "./translator/TranslatorFragmentAndroid"; +import MappingViewModelAndroid, { + MapBaasViewModel, +} from "./mapping/MappingViewModelAndroid"; +import TranslatorActivityAndroid from "./translator/TranslatorActivityAndroid"; +import { + mapRequestModels, + mapResponseModels, +} from "./mapping/MappingModelAndroid"; +import TranslatorMainActivityXml from "./translator/TranslatorMainActivityXml"; +import { + BenPascalCase, + StringCaser, +} from "@/components/WebExportReact/src/utils/helpers"; +import TranslatorFragmentXmlAndroid from "./translator/TranslatorFragmentXmlAndroid"; +import { gitIgnore } from "@/components/WebExportReact/src/utils/template"; +import AttrsValue from "./flatfile/AttrsValue"; +import TranslatorFragmentNavigations from "./translator/TranslatorFragmentNavigations"; +import AttrsThemes from "./flatfile/AttrsThemes"; +import AttrsDataExtractionRules from "./flatfile/AttrsDataExtractionRules"; +import AttrsBackupRules from "./flatfile/AttrsBackupRules"; +import AttrsFileProvider from "./flatfile/AttrsFileProvider"; +import generateStaticImages from "./flatfile/generateStaticImages"; +import generateDefaultAnim from "./flatfile/generateDefaultAnim"; +import generateDefaultFonts from "./flatfile/generateDefaultFonts"; +import GoogleServicesKey from "./flatfile/GoogleServicesKey"; +import RetrofitApiClient from "./flatfile/RetrofitApiClient"; +import ResourceAndroid from "./flatfile/ResourceAndroid"; +import BaseDataSource from "./flatfile/BaseDataSource"; +import MessageResponse from "./flatfile/MessageResponse"; +import AnimalModel from "./flatfile/AnimalModel"; +import ChatMessage from "./model/ChatMessage"; +import FileUtils from "./flatfile/FileUtils"; +import { generateAuthUI } from "./auth/auth"; +import { generateAlertUI } from "./alerts/alerts"; +import { JwtUtil } from "./flatfile/JwtUtil"; +import { generateBillingUI } from "./billing/billing"; +import { searchXML } from "./utils/search"; +import { Security } from "./flatfile/Security"; +import { generateOtherUI } from "./OtherUI/otherUi"; +import SimpleChatUtil from "./androidUtils/SimpleChatUtil"; +import SimpleChatView from "./widget/SimpleChatView"; + +/** + * @typedef {function(any, any): void} CallbackFunction + */ + +/** + * @param {*} configuration - The project configuration + * @param {"zip" | "copyList"} exportType - The export type + * @param {CallbackFunction} [cb=null] - The callback function + */ + +const AndroidBuilder = async (configuration, exportType, cb = null) => { + console.log("configuration"); + /** + * Steps: + * - Build package name + * - Build folders + * - Build android manifest file + * - Build SharedPreference file + * - Build MainActivity + * - Pull down all apis, make viewmodels + * - Make activities + * - Make fragments + * - Make gradle + */ + + try { + if (!configuration) { + throw new Error( + "Invalid Project configuration, please pass a valid project configuration data" + ); + } + + if (!["zip", "copyList"].includes(exportType)) { + throw new Error( + "Invalid Export Type, the export type must be 'zip | copyList'" + ); + } + const zip = new JSZip(); + const fileName = `baas_android_${configuration.name}.zip`; + let copyList = []; + let generated_files = []; + + zip.folder("app"); + zip.folder("app/src"); + zip.folder("app/src/main"); + zip.folder("app/src/main/res"); + zip.folder("app/src/main/res/anim"); + zip.folder("app/src/main/res/drawable"); + zip.folder("app/src/main/res/mipmap-hdpi"); + zip.folder("app/src/main/res/mipmap-mdpi"); + zip.folder("app/src/main/res/mipmap-xhdpi"); + zip.folder("app/src/main/res/mipmap-xxhdpi"); + zip.folder("app/src/main/res/mipmap-xxxhdpi"); + zip.folder("app/src/main/res/layout"); + zip.folder("app/src/main/res/menu"); + zip.folder("app/src/main/res/font"); + zip.folder("app/src/main/res/raw"); + zip.folder("app/src/main/res/values"); + zip.folder("app/src/main/java"); + zip.folder("app/src/main/java/com"); + + zip.folder("app/src/main/java/com/" + configuration.name.toLowerCase()); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/adapters" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/data" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/data/local" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/data/remote" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/di" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/utils" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/fcm" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/model" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/repositories" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/service" + ); + zip.folder( + "app/src/main/java/com/" + configuration.name.toLowerCase() + "/app/ui" + ); + zip.folder( + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/viewmodels" + ); + + //initialize copy list + copyList.push({ fileName: ".gitignore", content: gitIgnore() }); + copyList.push({ + fileName: "settings.gradle", + content: SettingGradle(configuration.projectId), + }); + copyList.push({ + fileName: "gradlew.bat", + content: Gradlewbat(configuration), + }); + copyList.push({ + fileName: "gradle.properties", + content: GradleProperties(configuration), + }); + // copyList.push({ + // fileName: "local.properties", + // content: "", + // }); + copyList.push({ + fileName: "build.gradle", + content: BuildGradle(configuration), + }); + copyList.push({ + fileName: ".gitignore", + content: GitIgnoreAndroid(configuration), + }); + // copyList.push({ + // fileName: "build.gradle", + // content: GitIgnoreAndroidApp(configuration), + // }); + copyList.push({ + fileName: "app/proguard-rules.pro", + content: ProguardRulesPro(configuration), + }); + copyList.push({ + fileName: "app/build.gradle", + content: BuildGradleApp( + configuration.name, + configuration.baseUrl, + btoa(`${configuration.projectId}:${configuration.secret}`) + ), + }); + copyList.push({ + fileName: "app/google-services.json", + content: GoogleServicesKey(), + }); + copyList.push({ + fileName: `app/src/main/AndroidManifest.xml`, + content: TranslatorManifestAndroid(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/App.kt", + content: TranslatorAppAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/MainActivity.kt", + content: TranslatorMainActivityAndroid(configuration), + }); + + //data values + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/data/local/AppPreferences.kt", + content: TranslatorLocalAppPreferenceAndroid(configuration), + }); + + //utils + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/utils/FileUtils.kt", + content: FileUtils(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/utils/JwtUtil.kt", + content: JwtUtil(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/utils/Security.kt", + content: Security(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/utils/SimpleChatUtil.kt", + content: SimpleChatUtil(configuration), + }); + + //auth + copyList = copyList.concat(generateAuthUI(configuration)); + //payment + copyList = copyList.concat(generateBillingUI(configuration)); + //alerts + copyList = copyList.concat(generateAlertUI(configuration)); + // other prebuilt UI + copyList = copyList.concat(generateOtherUI(configuration)); + + //search + if ( + configuration?.appBar?.some((bar) => + bar?.selectedActions?.includes("Search") + ) + ) { + copyList.push({ + fileName: "app/src/main/res/menu/search_menu.xml", + content: searchXML(configuration), + }); + } + + // //Cart + if ( + configuration?.appBar?.some((bar) => + bar?.selectedActions?.includes("Cart") + ) + ) { + copyList.push({ + fileName: "app/src/main/res/menu/cart_menu.xml", + content: ` + + + + + `, + }); + } + + //di folder + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/di/Modules.kt", + content: TranslatorModulesAndroid(configuration), + }); + + //network folder + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network/ApiService.kt", + content: TranslatorApiServiceAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network/BaseDataSource.kt", + content: BaseDataSource(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network/RemoteDataSource.kt", + content: TranslatorRemoteDataSourceAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network/Resource.kt", + content: ResourceAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/network/RetrofitApiClient.kt", + content: RetrofitApiClient(configuration), + }); + + //extensions values + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/Common.kt", + content: ExtensionCommonAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/Constants.kt", + content: TranslatorConstantAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/Enums.kt", + content: TranslatorEnumAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/FragmentDelegate.kt", + content: FragmentDelegate(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/StringExtensions.kt", + content: StringExtensionAndroid(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/extensions/View.kt", + content: ExtensionViewAndroid(configuration), + }); + + //fcm values + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/fcm/MyFirebasePushNotifications.kt", + content: MyFirebasePushNotifications(configuration), + }); + + //adapter values + //TODO + + //repository values + //TODO + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/repositories/APIRepository.kt", + content: TranslatorRepositoryAndroid(configuration), + }); + + //model values - Hold for now + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/" + + "MessageResponse.kt", + content: MessageResponse(configuration), + }); + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/" + + "AnimalModel.kt", + content: AnimalModel(configuration), + }); + + for (let i = 0; i < configuration.api.length; i++) { + const singleModel = configuration.api[i]; + if (!singleModel) continue; + // request + const singleModelObjectResult = mapRequestModels( + configuration, + singleModel + ); + if (typeof singleModelObjectResult !== "undefined") { + // if we don't have inputs then we don't need the request models + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/" + + singleModelObjectResult.fileName, + content: singleModelObjectResult.content, + }); + } + + // response + const singleResponseObjectResult = mapResponseModels( + configuration, + singleModel + ); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/" + + singleResponseObjectResult.fileName, + content: singleResponseObjectResult.content, + }); + } + + //viewmodel values + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/viewmodels/" + + "BaasViewModel.kt", + content: MapBaasViewModel(configuration), + }); + //TODO + // for (let i = 0; i < configuration.api.length; i++) { + // const singleModel = configuration.api[i]; + // if (!singleModel) continue + // const singleModelObjectResult = MappingViewModelAndroid( + // configuration, + // singleModel //TODO process this + // ); + // // "/app/viewmodels/" + + // // for now don't create view Models + // copyList.push({ + // fileName: + // "app/src/main/java/com/" + + // configuration.name.toLowerCase() + + // "/app/viewmodels/" + + // singleModelObjectResult.fileName, + // content: singleModelObjectResult.content, + // }); + // } + // Main Activity values + copyList.push({ + fileName: `app/src/main/java/com/${configuration.name.toLowerCase()}/app/MainActivity.kt`, + content: TranslatorMainActivityAndroid(configuration), + }); + + copyList = copyList.concat( + TranslatorMainActivityXml(configuration, configuration.activity) + ); + + //fragment values + //TODO + for (const element of configuration.fragment) { + const singleFragment = element; + const singleFragmentContent = TranslatorFragmentAndroid( + configuration, + singleFragment //TODO process this + ); + // console.log(singleFragmentContent); + copyList.push({ + fileName: `app/src/main/java/com/${configuration.name.toLowerCase()}/app/ui/fragments/${singleFragment.name.toLowerCase()}/${BenPascalCase( + singleFragment.name + )}Fragment.kt`, + content: singleFragmentContent, + }); + } + + copyList = copyList.concat( + TranslatorFragmentXmlAndroid( + configuration, + configuration.fragment //TODO process this + ) + ); + //anim + copyList = copyList.concat(await generateDefaultAnim()); + // drawable & minmap(s) + copyList = copyList.concat(await generateStaticImages()); + // font + copyList = copyList.concat(await generateDefaultFonts()); + + copyList.push({ + fileName: `app/src/main/res/navigation/mobile_navigation.xml`, + content: TranslatorFragmentNavigations( + configuration.fragment, + configuration + ), + }); + + //activity values + //TODO + // for (let i = 0; i < configuration.activity.length; i++) { + // const singleActivity = activity[i]; + // const singleActivityObjectResult = TranslatorActivityAndroid( + // configuration, + // singleActivity //TODO process this + // ); + // copyList.push({ + // fileName: + // "app/src/main/java/com/" + + // configuration.name.toLowerCase() + + // "/app/" + + // singleActivityObjectResult.fileName, + // content: singleActivityObjectResult.content, + // }); + // } + + //menu values + //TODO + + //res values + copyList.push({ + fileName: "app/src/main/res/values/attrs.xml", + content: AttrsValue(configuration), + }); + + copyList.push({ + fileName: "app/src/main/res/values/colors.xml", + content: AttrsColors(configuration), + }); + + copyList.push({ + fileName: "app/src/main/res/values/dimens.xml", + content: AttrsDimens(configuration), + }); + + copyList.push({ + fileName: "app/src/main/res/values/strings.xml", + content: AttrsStrings(configuration.name, configuration.fragment), + }); + copyList.push({ + fileName: "app/src/main/res/values/themes.xml", + content: AttrsThemes(configuration.name, configuration.fragment), + }); + copyList.push({ + fileName: "app/src/main/res/xml/data_extraction_rules.xml", + content: AttrsDataExtractionRules( + configuration.name, + configuration.fragment + ), + }); + copyList.push({ + fileName: "app/src/main/res/xml/backup_rules.xml", + content: AttrsBackupRules(configuration.name, configuration.fragment), + }); + copyList.push({ + fileName: "app/src/main/res/xml/file_provider.xml", + content: AttrsFileProvider(configuration.name, configuration.fragment), + }); + + copyList.push({ + fileName: `app/src/main/res/menu/${ + configuration.nav !== "bottomBar" + ? "navigation_menu" + : "bottom_nav_menu" + }.xml`, + content: AttrsMenuDrawer(configuration.name, configuration.menu), + }); + + //copy list into zip + copyList.forEach((singleCopy) => { + zip.file(singleCopy.fileName, singleCopy.content); + }); + + if (exportType === "zip") { + zip.generateAsync({ type: "blob" }).then(function (content) { + saveAs(content, fileName); + }); + if (cb) { + cb(null, "Zip Exported"); + } + } else if (exportType === "copyList") { + if (cb) { + cb(null, copyList); + } else { + return copyList; + } + } + } catch (e) { + console.log("Builder Error: ", e); + if (cb) { + cb(e.message, null); + } + return { error: e.message }; + } +}; +export default AndroidBuilder; diff --git a/src/components/builder/BackendBuilder.tsx b/src/components/builder/BackendBuilder.tsx new file mode 100644 index 0000000..ada853b --- /dev/null +++ b/src/components/builder/BackendBuilder.tsx @@ -0,0 +1,2 @@ +const BackendBuilder = (props) => {}; +export default BackendBuilder; diff --git a/src/components/builder/OtherUI/adapter/ChatRoomAdapter.tsx b/src/components/builder/OtherUI/adapter/ChatRoomAdapter.tsx new file mode 100644 index 0000000..bae0ab1 --- /dev/null +++ b/src/components/builder/OtherUI/adapter/ChatRoomAdapter.tsx @@ -0,0 +1,66 @@ +export default (configuration) => { + return ` + + package ${configuration.packageName}.adapters + + import ${configuration.name}.R + import android.content.Context + import android.view.LayoutInflater + import android.view.View + import android.view.ViewGroup + import android.widget.TextView + import android.widget.ImageView + import androidx.recyclerview.widget.RecyclerView + import ${configuration.packageName}.extensions.loadImageFromUrl + import androidx.navigation.findNavController + import ${configuration.packageName}.model.remote.ChatRoomListResponse + import ${configuration.packageName}.model.remote.ChatRoomResponse + + + class ChatRoomAdapter( + private var dataset: List + ): RecyclerView.Adapter() { + + var onItemClick: ((ChatRoomListResponse) -> Unit)? = null + + inner class ViewHolder(private val view: View): RecyclerView.ViewHolder(view) { + + init { + + view.setOnClickListener{ + onItemClick?.invoke(dataset[adapterPosition]) + } + } + + fun bind(model: ChatRoomListResponse) { + view.findViewById(R.id.data_id).text = "Room ID: "+model.id + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val adapterLayout = LayoutInflater.from(parent.context) + .inflate(R.layout.room_data, parent, false) + + return ViewHolder(adapterLayout) + } + + override fun getItemCount(): Int { + return dataset.size; + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val item = dataset[position] + holder.bind(item) + } + + fun updateData(newData: List) { + dataset = newData + notifyDataSetChanged() + } + } + + + + `; + }; + \ No newline at end of file diff --git a/src/components/builder/OtherUI/adapter/FriendListAdapter.tsx b/src/components/builder/OtherUI/adapter/FriendListAdapter.tsx new file mode 100644 index 0000000..84349dd --- /dev/null +++ b/src/components/builder/OtherUI/adapter/FriendListAdapter.tsx @@ -0,0 +1,78 @@ +export default (configuration) => { + return ` + + package ${configuration.packageName}.adapters + + import ${configuration.name}.R + import android.content.Context + import android.view.LayoutInflater + import android.view.View + import android.view.ViewGroup + import android.widget.TextView + import android.widget.ImageView + import androidx.recyclerview.widget.RecyclerView + + import com.manaknight.app.model.remote.GetOneUserResponse + + + class FriendListAdapter( + private var dataset: List + ): RecyclerView.Adapter() { + +var onItemClick: ((GetOneUserResponse) -> Unit)? = null + +inner class ViewHolder(private val view: View): RecyclerView.ViewHolder(view) { + +init { + +view.setOnClickListener{ +onItemClick?.invoke(dataset[adapterPosition]) +} +} + +fun bind(model: GetOneUserResponse) { +var fName = model.first_name +var lName = model.last_name +if (fName == null) { +fName = "No First Name" +} else if (fName.isEmpty()) { +fName = "No First Name" +} + +if (lName == null) { +lName = "No Last Name" +} else if (lName.isEmpty()) { +lName = "No First Name" +} + +view.findViewById(R.id.data_id).text = fName + " " + lName +} +} + +override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { +val adapterLayout = LayoutInflater.from(parent.context) +.inflate(R.layout.user_data, parent, false) + +return ViewHolder(adapterLayout) +} + +override fun getItemCount(): Int { +return dataset.size; +} + +override fun onBindViewHolder(holder: ViewHolder, position: Int) { +val item = dataset[position] +holder.bind(item) +} + +fun updateData(newData: List) { +dataset = newData +notifyDataSetChanged() +} +} + + + + `; + }; + \ No newline at end of file diff --git a/src/components/builder/OtherUI/adapter/SimpleChatAdapter.tsx b/src/components/builder/OtherUI/adapter/SimpleChatAdapter.tsx new file mode 100644 index 0000000..82d1298 --- /dev/null +++ b/src/components/builder/OtherUI/adapter/SimpleChatAdapter.tsx @@ -0,0 +1,414 @@ +export default (configuration) => { + return ` + + + + package ${configuration.packageName}.ui.adapter + + import ${configuration.name}.databinding.ReceiveImageMessageItemBinding + import ${configuration.name}.databinding.ReceiveTextMessageItemBinding + import ${configuration.name}.databinding.ReceiveVideoMessageItemBinding + import ${configuration.name}.databinding.SendImageMessageItemBinding + import ${configuration.name}.databinding.SendTextMessageItemBinding + import ${configuration.name}.databinding.SendVideoMessageItemBinding + import android.annotation.SuppressLint + import android.content.Context + import android.view.LayoutInflater + import android.view.ViewGroup + import androidx.recyclerview.widget.DiffUtil + import androidx.recyclerview.widget.RecyclerView + import com.bumptech.glide.Glide + import com.bumptech.glide.request.RequestOptions + import ${configuration.packageName}.model.remote.ChatMessage + import ${configuration.packageName}.model.remote.SingleChatResponse + import ${configuration.packageName}.utils.SimpleChatUtil.Companion.getTimeAgo + import ${configuration.packageName}.widget.SimpleChatView.Companion.TYPE_IMAGE + import ${configuration.packageName}.widget.SimpleChatView.Companion.TYPE_TEXT + import ${configuration.packageName}.widget.SimpleChatView.Companion.TYPE_VIDEO + + + + + + class SimpleChatAdapter(private val context: Context) : + RecyclerView.Adapter() { + + private var chatMessage: ArrayList = arrayListOf() + private var onChatImageClickListener: ((SingleChatResponse) -> Unit)? = null + private var onChatVideoClickListener: ((SingleChatResponse) -> Unit)? = null + private var onChatUserImageClickListener: ((SingleChatResponse) -> Unit)? = null + private var onChatUsernameClickListener: ((SingleChatResponse) -> Unit)? = null + private var onMessageClickListener:((SingleChatResponse)->Unit)? = null + private var userId = 0 + + companion object { + const val TYPE_TEXT_RIGHT = 0 + const val TYPE_TEXT_LEFT = 1 + const val TYPE_IMAGE_RIGHT = 2 + const val TYPE_IMAGE_LEFT = 3 + const val TYPE_VIDEO_RIGHT = 4 + const val TYPE_VIDEO_LEFT = 5 + } + + inner class SimpleChatDiffUtil( + private val oldList: List, + private val newList: List + ) : DiffUtil.Callback() { + override fun getOldListSize(): Int { + return oldList.size + } + + override fun getNewListSize(): Int { + return newList.size + } + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition].id == newList[newItemPosition].id + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition] == newList[newItemPosition] + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + TYPE_TEXT_RIGHT -> { + TypeTextSend( + SendTextMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + TYPE_TEXT_LEFT -> { + TypeTextReceive( + ReceiveTextMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + TYPE_IMAGE_RIGHT -> { + TypeImageSend( + SendImageMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + TYPE_IMAGE_LEFT -> { + TypeImageReceive( + ReceiveImageMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + TYPE_VIDEO_RIGHT -> { + TypeVideoSend( + SendVideoMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + else -> { + TypeVideoReceive( + ReceiveVideoMessageItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + + if (chatMessage[position].chat?.user_id == this.userId) { + if (chatMessage[position].chat?.is_image == true) { + (holder as TypeImageSend).bind(position) + } else { + (holder as TypeTextSend).bind(position) + } + } else { + if (chatMessage[position].chat?.is_image == true) { + (holder as TypeImageReceive).bind(position) + } else { + (holder as TypeTextReceive).bind(position) + } + } + /*when(chatMessage[position].view_type){ + + + + TYPE_TEXT_RIGHT->(holder as TypeTextSend).bind(position) + TYPE_TEXT_LEFT->(holder as TypeTextReceive).bind(position) + TYPE_IMAGE_RIGHT->(holder as TypeImageSend).bind(position) + TYPE_IMAGE_LEFT->(holder as TypeImageReceive).bind(position) + TYPE_VIDEO_RIGHT->(holder as TypeVideoSend).bind(position) + TYPE_VIDEO_LEFT->(holder as TypeVideoReceive).bind(position) + }*/ + } + + override fun getItemCount(): Int { + return chatMessage.size + } + + override fun getItemViewType(position: Int): Int { + var isFromMe = false + if (chatMessage[position].chat?.user_id == this.userId) { + isFromMe = true + } + + var viewType = 0 + + if (chatMessage[position].chat?.is_image == true) { + if (isFromMe) + viewType = 2 + else + viewType = 3 + } else { + if (isFromMe) + viewType = 0 + else + viewType = 1 + } + + /*val viewType = when (chatMessage[position].message_type) { + TYPE_TEXT -> { + if (isFromMe) + 0 + else + 1 + } + TYPE_IMAGE -> { + if (isFromMe) + 2 + else + 3 + } + TYPE_VIDEO -> { + if (isFromMe) + 4 + else + 5 + } + else -> throw RuntimeException("MessageType in ChatMessage() is not added") + }*/ + chatMessage[position].view_type = viewType + return viewType + } + + inner class TypeTextSend(private val binding: SendTextMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + txtMessage.text = chatMessage[position].chat?.message ?: "" + + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + txtMessage.setOnClickListener { + onMessageClickListener?.invoke(chatMessage[position]) + } + + } + } + } + + inner class TypeTextReceive(private val binding: ReceiveTextMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + txtMessage.text = chatMessage[position].chat?.message ?: "" + + //txtUsername.text = chatMessage[position].username + txtUsername.text = "" + + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + /*Glide.with(context) + .load(chatMessage[position].profile_url) + .apply(RequestOptions.circleCropTransform()) + .into(imgProfile)*/ + + txtMessage.setOnClickListener { + onMessageClickListener?.invoke(chatMessage[position]) + } + + } + } + } + + inner class TypeImageSend(private val binding: SendImageMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + Glide.with(context) + .load(chatMessage[position].chat?.message ?: "") + .into(imgMessage) + + imgMessage.setOnClickListener { + onChatImageClickListener?.invoke(chatMessage[position]) + } + } + } + } + + inner class TypeImageReceive(private val binding: ReceiveImageMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + //txtUsername.text = chatMessage[position].username + txtUsername.text = "" + + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + /*Glide.with(context) + .load(chatMessage[position].profile_url) + .apply(RequestOptions.circleCropTransform()) + .into(imgProfile)*/ + + Glide.with(context) + .load(chatMessage[position].chat?.message ?: "") + .into(imgMessage) + + imgMessage.setOnClickListener { + onChatImageClickListener?.invoke(chatMessage[position]) + } + + imgProfile.setOnClickListener { + onChatUserImageClickListener?.invoke(chatMessage[position]) + } + + txtUsername.setOnClickListener { + onChatUsernameClickListener?.invoke(chatMessage[position]) + } + } + } + } + + inner class TypeVideoSend(private val binding: SendVideoMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + Glide.with(context) + .load(chatMessage[position].chat?.message ?: "") + .into(imgMessage) + + + imgMessage.setOnClickListener { + onChatImageClickListener?.invoke(chatMessage[position]) + } + } + } + } + + inner class TypeVideoReceive(private val binding: ReceiveVideoMessageItemBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(position: Int) { + binding.apply { + + //txtUsername.text = chatMessage[position].username + txtUsername.text = "" + txtDate.text = getTimeAgo(chatMessage[position].chat?.timestamp ?: 0) + + /*Glide.with(context) + .load(chatMessage[position].profile_url) + .apply(RequestOptions.circleCropTransform()) + .into(imgProfile)*/ + + Glide.with(context) + .load(chatMessage[position].chat?.message ?: "") + .into(imgMessage) + + imgMessage.setOnClickListener { + onChatImageClickListener?.invoke(chatMessage[position]) + } + + imgProfile.setOnClickListener { + onChatUserImageClickListener?.invoke(chatMessage[position]) + } + + txtUsername.setOnClickListener { + onChatUsernameClickListener?.invoke(chatMessage[position]) + } + } + } + } + + + fun setUserID(userID:Int) { + this.userId = userID + } + + fun setOnChatImageClickListener(listener: (SingleChatResponse) -> Unit) { + onChatImageClickListener = listener + } + + fun setOnChatVideoClickListener(listener: (SingleChatResponse) -> Unit) { + onChatVideoClickListener = listener + } + + fun setOnChatUserImageClickListener(listener: (SingleChatResponse) -> Unit) { + onChatUserImageClickListener = listener + } + + fun setOnChatUsernameClickListener(listener: (SingleChatResponse) -> Unit) { + onChatUsernameClickListener = listener + } + + fun setOnMessageClickListener(listener: (SingleChatResponse) -> Unit) { + onMessageClickListener = listener + } + + fun addData(newList: List){ + //chatMessage.clear() + val diffResult = DiffUtil.calculateDiff(SimpleChatDiffUtil(chatMessage,newList)) + chatMessage.addAll(chatMessage.union(newList)) + diffResult.dispatchUpdatesTo(this) + } + + fun addData(chatMessage: SingleChatResponse){ + this.chatMessage.add(chatMessage) + notifyItemInserted(this.chatMessage.size-1) + } + + @SuppressLint("NotifyDataSetChanged") + fun remove(chatMessage: SingleChatResponse){ + this.chatMessage.remove(chatMessage) + notifyDataSetChanged() + } + + @SuppressLint("NotifyDataSetChanged") + fun remove(position: Int){ + chatMessage.removeAt(position) + notifyDataSetChanged() + } + + @SuppressLint("NotifyDataSetChanged") + fun clearMessages(){ + chatMessage.clear() + notifyDataSetChanged() + } + +} + `; + }; + \ No newline at end of file diff --git a/src/components/builder/OtherUI/adapter/VideosAdapter.tsx b/src/components/builder/OtherUI/adapter/VideosAdapter.tsx new file mode 100644 index 0000000..2321339 --- /dev/null +++ b/src/components/builder/OtherUI/adapter/VideosAdapter.tsx @@ -0,0 +1,51 @@ +export default (configuration) => { + return ` + + package ${configuration.packageName}.adapters + + + import ${configuration.name}.databinding.ItemBroadcastVideoBinding + import android.view.LayoutInflater + import android.view.ViewGroup + import androidx.recyclerview.widget.RecyclerView + import ${configuration.packageName}.model.remote.GetVideoListResponse + + + class VideosAdapter(var list: List) : + RecyclerView.Adapter() { + override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolderItem { + val binding = + ItemBroadcastVideoBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) + return ViewHolderItem(binding) + } + + override fun onBindViewHolder(viewHolderItem: ViewHolderItem, i: Int) { + val category = list[i] + + //viewHolderItem.binding.imageView.loadImageFromUrl(category.video_url) + viewHolderItem.binding.tvName.text = category.title + viewHolderItem.binding.tvCountry.text = "" + viewHolderItem.binding.tvUploadTime.text = category.update_at + viewHolderItem.binding.tvPrice.text = category.price + + } + + override fun getItemCount(): Int { + return list.size + } + + inner class ViewHolderItem(var binding: ItemBroadcastVideoBinding) : RecyclerView.ViewHolder( + binding.root + ) + + fun updateData(newData: List) { + list = newData + notifyDataSetChanged() + } +} + + + + `; + }; + \ No newline at end of file diff --git a/src/components/builder/OtherUI/data/ChatRoomRecyclerData.tsx b/src/components/builder/OtherUI/data/ChatRoomRecyclerData.tsx new file mode 100644 index 0000000..da2cb70 --- /dev/null +++ b/src/components/builder/OtherUI/data/ChatRoomRecyclerData.tsx @@ -0,0 +1,36 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + + import ${configuration.name}.R + import androidx.lifecycle.LifecycleOwner + import ${configuration.packageName}.adapters.ChatRoomAdapter + import ${configuration.packageName}.adapters.DataRecyclerAdapter + import ${configuration.packageName}.extensions.hideSoftKeyboard + import ${configuration.packageName}.extensions.snackBar + import ${configuration.packageName}.model.remote.ChatRoomListResponse + import ${configuration.packageName}.network.Status + import ${configuration.packageName}.viewmodels.BaasViewModel + import java.io.Serializable + + + + fun loadDataData(viewLifecycleOwner: LifecycleOwner, baasViewModel: BaasViewModel, userId: Int, adapter: ChatRoomAdapter) { + + baasViewModel.getAllRoom(userId).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> println(it.message ?: "Something went wrong") + Status.LOADING -> { + + } + + Status.SUCCESS -> { + + it.data?.let { it1 -> adapter.updateData(it1.list) } + } + } + } + } + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/data/FriendListRecyclerData.tsx b/src/components/builder/OtherUI/data/FriendListRecyclerData.tsx new file mode 100644 index 0000000..c8f119c --- /dev/null +++ b/src/components/builder/OtherUI/data/FriendListRecyclerData.tsx @@ -0,0 +1,38 @@ +export default (configuration) => { + return `package com.manaknight.app.data + + import Manaknight.R + import androidx.lifecycle.LifecycleOwner + import com.manaknight.app.adapters.ChatRoomAdapter + import com.manaknight.app.adapters.DataRecyclerAdapter + import com.manaknight.app.adapters.FriendListAdapter + import com.manaknight.app.extensions.hideSoftKeyboard + import com.manaknight.app.extensions.snackBar + import com.manaknight.app.model.remote.ChatRoomListResponse + import com.manaknight.app.network.Status + import com.manaknight.app.viewmodels.BaasViewModel + import java.io.Serializable + + + + fun loadAllUserData(viewLifecycleOwner: LifecycleOwner, baasViewModel: BaasViewModel, userId: Int, adapter: FriendListAdapter) { + + baasViewModel.getAllUser().observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> println(it.message ?: "Something went wrong") + Status.LOADING -> { + + } + + Status.SUCCESS -> { + + it.data?.let { it1 -> adapter.updateData(it1.list) } + } + } + } + } + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/drawables/Drawables.tsx b/src/components/builder/OtherUI/drawables/Drawables.tsx new file mode 100644 index 0000000..859bf46 --- /dev/null +++ b/src/components/builder/OtherUI/drawables/Drawables.tsx @@ -0,0 +1,10 @@ +export default () => { + + + + return ` + + + + ` + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/fragment/ChatUiFragment.tsx b/src/components/builder/OtherUI/fragment/ChatUiFragment.tsx new file mode 100644 index 0000000..db09d80 --- /dev/null +++ b/src/components/builder/OtherUI/fragment/ChatUiFragment.tsx @@ -0,0 +1,376 @@ +export default (configuration) => { + return ` + + + + package ${configuration.packageName}.ui + + import ${configuration.name}.databinding.FragmentHomeBinding + import android.app.Activity + import android.content.Intent + import android.graphics.Bitmap + import android.graphics.Color + import android.net.Uri + import android.os.Handler + import android.os.Looper + import android.os.Message + import android.provider.MediaStore + import android.widget.Toast + import android.widget.VideoView + import androidx.activity.result.ActivityResultCallback + import androidx.activity.result.ActivityResultLauncher + import androidx.activity.result.contract.ActivityResultContracts + import androidx.navigation.fragment.findNavController + import ${configuration.packageName}.extensions.RequestCodes + import ${configuration.packageName}.extensions.hideSoftKeyboard + import ${configuration.packageName}.extensions.loadImageFromUrl + import ${configuration.packageName}.extensions.snackBar + import ${configuration.packageName}.extensions.viewBinding + import ${configuration.packageName}.model.remote.ChatMessage + import ${configuration.packageName}.model.remote.SingleChatMessageResponse + import ${configuration.packageName}.model.remote.SingleChatResponse + import ${configuration.packageName}.utils.FileUtils.saveImage + import ${configuration.packageName}.viewmodels.BaasViewModel + import ${configuration.packageName}.widget.SimpleChatView + import kotlinx.coroutines.CoroutineScope + import kotlinx.coroutines.Dispatchers + import kotlinx.coroutines.launch + import okhttp3.MediaType.Companion.toMediaTypeOrNull + import okhttp3.MultipartBody + import okhttp3.RequestBody.Companion.asRequestBody + import org.jetbrains.annotations.Nullable + import org.koin.android.ext.android.inject + import org.koin.androidx.viewmodel.ext.android.viewModel + import java.io.File + import java.io.IOException + import java.util.Date + import java.util.UUID + + + class ChatUiFragment : Fragment(R.layout.fragment_chat_ui) { + + private val binding by viewBinding(FragmentChatUiBinding::bind) + private val baasViewModel: BaasViewModel by viewModel() + private val pref by inject() + + var userId = pref.userId + + + + private var chatMessageList:ArrayList = arrayListOf() + private val position = 0 + lateinit var room_id:String + lateinit var mainHandler: Handler + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mainHandler = Handler(Looper.getMainLooper()) + + room_id = arguments?.getString("roomid").toString() + + val simpleChatView = binding.simpleChatView + simpleChatView.userId = this.userId!! + + /* //sending text message + simpleChatView.addMessage( + ChatMessage( + UUID.randomUUID().toString(),//message id + "Hello world",//message + "John Doe",//username + "http://www.maxspring.ch/images/cartoons/4.jpg",//profile url + false,//for setting left or right position of the chat + System.currentTimeMillis(),//timestamp + SimpleChatView.TYPE_TEXT//message type + ) + ) + + //sending image message + simpleChatView.addMessage( + ChatMessage( + UUID.randomUUID().toString(),//message id + "http://www.maxspring.ch/images/cartoons/c71.png",//image url + "John Doe",//username + "http://www.maxspring.ch/images/cartoons/4.jpg",//profile url + true,//for setting left or right position of the chat + System.currentTimeMillis(),//timestamp + SimpleChatView.TYPE_IMAGE//message type + ) + ) + + //sending video message + simpleChatView.addMessage( + ChatMessage( + UUID.randomUUID().toString(),//message id + "http://www.maxspring.ch/images/cartoons/Kultursponsoring.jpg",//video url + "John Doe",//username + "http://www.maxspring.ch/images/cartoons/4.jpg",//profile url + true,//for setting left or right position of the chat + System.currentTimeMillis(),//timestamp + SimpleChatView.TYPE_VIDEO//message type + ) + )*/ + + + //adding list of messages + //simpleChatView.addMessage(chatMessageList) + + + //removing message + //simpleChatView.remove(position) + + //simpleChatView.remove(ChatMessage()) + + //simpleChatView.clearMessages()//clears all the added messages + + + simpleChatView.setOnMessageSendListener { message -> + //user clicked on send message button + + sendTextMessage(room_id, message) + + /*simpleChatView.addMessage( + ChatMessage( + UUID.randomUUID().toString(),//message id + message,//message + "John Doe",//username + "http://www.maxspring.ch/images/cartoons/4.jpg",//profile url + true,//for setting left or right position of the chat + System.currentTimeMillis(),//timestamp + SimpleChatView.TYPE_TEXT//message type + ) + )*/ + } + + simpleChatView.setOnMessageClickListener { chatMessage -> + //user clicked on the Text Message + } + + simpleChatView.setOnChatImageClickListener { chatMessage -> + //user clicked on the image message + } + + simpleChatView.setOnChatVideoClickListener { chatMessage -> + //user clicked on the video message + } + + simpleChatView.setOnChatUserImageClickListener { chatMessage -> + //user clicked on the profile pic + } + + simpleChatView.setOnChatUsernameClickListener { chatMessage -> + //user clicked on the username + } + + + simpleChatView.setOnSelectImageClickListener { + //user clicked on the image selection button + + /*val chatMessage = SingleChatResponse(0, room_id.toInt(), 1, "", "", 0, + SingleChatMessageResponse("http://www.maxspring.ch/images/cartoons/c71.png", this.userId, true, Date().time)) + + binding.simpleChatView.addMessage(chatMessage)*/ + + val intent = Intent().apply { + type = "image/*" + action = Intent.ACTION_GET_CONTENT + } + startActivityForResult( + Intent.createChooser(intent, "Select image"), RequestCodes.GALLERY_IMAGE + ) + } + + simpleChatView.setOnSelectVideoClickListener { + //user clicked on the video selection button + } + + simpleChatView.setOnSelectCameraClickListener { + //user clicked on the camera button + + /*val chatMessage = SingleChatResponse(0, room_id.toInt(), 1, "", "", 0, + SingleChatMessageResponse("http://www.maxspring.ch/images/cartoons/c71.png", this.userId, true, Date().time)) + + binding.simpleChatView.addMessage(chatMessage)*/ + + startActivityForResult( + Intent(MediaStore.ACTION_IMAGE_CAPTURE), RequestCodes.CAMERA_IMAGE + ) + } + + + simpleChatView.setChatViewBackground(Color.WHITE) + simpleChatView.setSendButtonColor(Color.BLUE) + simpleChatView.setAddButtonColor(Color.RED) + simpleChatView.setChatInputBackgroundColor(Color.LTGRAY) + simpleChatView.setChatInputBackground(R.drawable.chat_input_shape) + simpleChatView.setShowAddButton(true or false) + simpleChatView.setShowSenderLayout(true or false) + simpleChatView.setShowImageButton(true or false) + simpleChatView.setShowVideoButton(false) + simpleChatView.setShowCameraButton(true or false) + simpleChatView.setHint("Type message...") + simpleChatView.setHintTextColor(Color.parseColor("#929292")) + simpleChatView.setTextColor(Color.BLACK) + + getAllChats(room_id) + + startPooling() + } + + override fun onPause() { + super.onPause() + mainHandler.removeCallbacks(updateTextTask) + } + + override fun onResume() { + super.onResume() + mainHandler.post(updateTextTask) + } + + private val updateTextTask = object : Runnable { + override fun run() { + minusOneSecond() + mainHandler.postDelayed(this, 5000) + } + } + + fun minusOneSecond() { + //getAllChats(room_id) + } + + private fun uploadProfileImage(image: Bitmap) { + val file = File(saveImage(image)) + val contentType = "multipart/form-data".toMediaTypeOrNull() + val part = MultipartBody.Part.createFormData( + "file", file.name, file.asRequestBody(contentType) + ) + baasViewModel.uploadimages3( part ).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> { + snackBar(it.message ?: "Something went wrong") + } + Status.LOADING -> { + snackBar("sending message...") + } + Status.SUCCESS -> { + //pref.photo = it.data?.url + //binding.ivUser.loadImageFromUrl(pref.photo) + + val chatMessage = SingleChatResponse(0, room_id.toInt(), 1, "", "", 0, + SingleChatMessageResponse(it.data?.url, this.userId, true, Date().time)) + + binding.simpleChatView.addMessage(chatMessage) + } + } + } + } + + + fun sendTextMessage(room_id: String, message: String) { + + requireActivity().hideSoftKeyboard() + baasViewModel.sendTextMessage(room_id, this.userId!!, message).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong)) + Status.LOADING -> { + snackBar("sending message...") + } + + Status.SUCCESS -> { + //getAllChats(room_id) + + val chatMessage = SingleChatResponse(0, room_id.toInt(), 1, "", "", 0, + SingleChatMessageResponse(message, this.userId, false, Date().time)) + //chatMessageList.add(chatMessage) + + binding.simpleChatView.addMessage(chatMessage) + } + } + } + } + + fun getAllChats(room_id: String) { + + requireActivity().hideSoftKeyboard() + baasViewModel.getChats(room_id).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong)) + Status.LOADING -> { + //snackBar("loading list...") + } + + Status.SUCCESS -> { + val chatList = it.data?.model + if (chatList != null) { + chatMessageList.clear() + chatMessageList.addAll(chatList) + + val simpleChatView = binding.simpleChatView + simpleChatView.setUserID(this.userId!!) + simpleChatView.addMessage(chatMessageList) + } + } + } + } + } + + fun startPooling() { + + requireActivity().hideSoftKeyboard() + baasViewModel.getStartPool(this.userId!!).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> { + + startPooling() + //snackBar(it.message ?: getString(R.string.something_went_wrong)) + } + Status.LOADING -> { + //snackBar("loading list...") + + } + + Status.SUCCESS -> { + it.data?.timestamp = Date().time + val chatMessage = SingleChatResponse(0, room_id.toInt(), 1, "", "", 0, it.data) + //chatMessageList.add(chatMessage) + binding.simpleChatView.addMessage(chatMessage) + startPooling() + } + } + } + } + + @Deprecated("Deprecated in Java") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (data != null) { + if (requestCode == RequestCodes.GALLERY_IMAGE) { + val contentURI: Uri? = data.data + try { + val bitmap = + MediaStore.Images.Media.getBitmap(activity?.contentResolver, contentURI) + uploadProfileImage(bitmap) + } catch (e: IOException) { + e.printStackTrace() + Toast.makeText(context, "Failed!", Toast.LENGTH_SHORT).show() + } + } + if (requestCode == RequestCodes.CAMERA_IMAGE) { + try { + val bitmap = data.extras?.get("data") as Bitmap + uploadProfileImage(bitmap) + } catch (e: IOException) { + e.printStackTrace() + Toast.makeText(context, "Failed!", Toast.LENGTH_SHORT).show() + } + } + } + } + + } + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/fragment/FriendListFragment.tsx b/src/components/builder/OtherUI/fragment/FriendListFragment.tsx new file mode 100644 index 0000000..2145606 --- /dev/null +++ b/src/components/builder/OtherUI/fragment/FriendListFragment.tsx @@ -0,0 +1,72 @@ +export default (configuration) => { + return ` + + + + package com.manaknight.app.ui.fragments.chatui + + import Manaknight.R + import Manaknight.databinding.FragmentFriendListBinding + import Manaknight.databinding.FragmentRoomListBinding + import android.os.Bundle + import android.view.Menu + import android.view.MenuInflater + import android.view.View + import androidx.core.os.bundleOf + import androidx.fragment.app.Fragment + import androidx.navigation.fragment.findNavController + import androidx.recyclerview.widget.LinearLayoutManager + import com.manaknight.app.adapters.ChatRoomAdapter + import com.manaknight.app.adapters.FriendListAdapter + import com.manaknight.app.data.loadAllUserData + import com.manaknight.app.data.loadDataData + import com.manaknight.app.data.local.AppPreferences + import com.manaknight.app.extensions.viewBinding + import com.manaknight.app.viewmodels.BaasViewModel + import org.koin.android.ext.android.inject + import org.koin.androidx.viewmodel.ext.android.viewModel + + class FriendListFragment : Fragment(R.layout.fragment_friend_list) { + + private val binding by viewBinding(FragmentFriendListBinding::bind) + private val baasViewModel: BaasViewModel by viewModel() + private val pref by inject() + var userId = pref.userId + + private lateinit var adapterData: FriendListAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + // binding.icBack.setOnClickListener { findNavController().popBackStack() } + + + val recyclerview637093b5 = binding.recyclerview637093b5 + adapterData = FriendListAdapter(emptyList()) + recyclerview637093b5.layoutManager = LinearLayoutManager(requireContext()) + + + loadAllUserData(viewLifecycleOwner, baasViewModel, userId!!, adapterData) + recyclerview637093b5.adapter = adapterData + + + adapterData.onItemClick = { singleUser -> + + val args = Bundle() + args.putString("otherUserID", ""+singleUser.id) + + + findNavController().navigate(R.id.action_to_room_Fragment, args) + } + } + + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + + val inflater = inflater + } + } + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/fragment/RoomListFragment.tsx b/src/components/builder/OtherUI/fragment/RoomListFragment.tsx new file mode 100644 index 0000000..7385401 --- /dev/null +++ b/src/components/builder/OtherUI/fragment/RoomListFragment.tsx @@ -0,0 +1,151 @@ +export default (configuration) => { + return ` + package com.manaknight.app.ui.fragments.chatui + + import Manaknight.R + import Manaknight.databinding.FragmentRoomListBinding + import android.os.Bundle + import android.view.Menu + import android.view.MenuInflater + import android.view.MenuItem + import android.view.View + import androidx.core.os.bundleOf + import androidx.fragment.app.Fragment + import androidx.lifecycle.LifecycleOwner + import androidx.navigation.fragment.findNavController + import androidx.recyclerview.widget.LinearLayoutManager + import com.manaknight.app.adapters.ChatRoomAdapter + import com.manaknight.app.adapters.FriendListAdapter + import com.manaknight.app.data.loadAllUserData + import com.manaknight.app.data.loadDataData + import com.manaknight.app.data.local.AppPreferences + import com.manaknight.app.extensions.viewBinding + import com.manaknight.app.model.remote.ChatRoomListResponse + import com.manaknight.app.network.Status + import com.manaknight.app.viewmodels.BaasViewModel + import org.koin.android.ext.android.inject + import org.koin.androidx.viewmodel.ext.android.viewModel + + class RoomListFragment : Fragment(R.layout.fragment_room_list) { + + private val binding by viewBinding(FragmentRoomListBinding::bind) + private val baasViewModel: BaasViewModel by viewModel() + private val pref by inject() + var userId = pref.userId + lateinit var otherUserID:String + + private lateinit var adapterData: ChatRoomAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + // binding.icBack.setOnClickListener { findNavController().popBackStack() } + + otherUserID = arguments?.getString("otherUserID").toString() + + val recyclerview637093b5 = binding.recyclerview637093b5 + adapterData = ChatRoomAdapter(emptyList()) + recyclerview637093b5.layoutManager = LinearLayoutManager(requireContext()) + + + loadRoomData(viewLifecycleOwner, baasViewModel, userId!!, otherUserID.toInt(), adapterData) + recyclerview637093b5.adapter = adapterData + + + adapterData.onItemClick = { roomModel -> + + val args = Bundle() + args.putString("roomid", ""+roomModel.id) + + + findNavController().navigate(R.id.action_loginFragment_to_chatFragment, args) + } + + //setHasOptionsMenu(true) + binding.addRoom.setOnClickListener { + + createRoom(userId!!, otherUserID.toInt()) + } + } + + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + + val inflater = inflater + + //inflater.inflate(R.menu.add_menu, menu) + + //val searchItem: MenuItem = menu.findItem(R.id.alerts) + + /*val searchView: SearchView = searchItem.getActionView() as SearchView + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener, + android.widget.SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(p0: String?): Boolean { + return false + } + + override fun onQueryTextChange(msg: String): Boolean { + + filter(msg) + return false + } + })*/ + //return true + } + + fun loadRoomData(viewLifecycleOwner: LifecycleOwner, baasViewModel: BaasViewModel, userId: Int, otherUserId: Int, adapter: ChatRoomAdapter) { + + baasViewModel.getAllRoom(userId).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> println(it.message ?: "Something went wrong") + Status.LOADING -> { + + } + + Status.SUCCESS -> { + + it.data?.let { + + var roomList = mutableListOf() + for (list in it.list) { + if ((list.user_id == userId && list.other_user_id == otherUserId) + || (list.user_id == otherUserId && list.other_user_id == userId)) { + + roomList.add(list) + } + } + adapter.updateData(roomList) + if(roomList.count() > 0) { + binding.addRoom.visibility = View.GONE + } + } + } + } + } + } + + + fun createRoom(userId: Int, otherUserId: Int) { + + baasViewModel.CreateRoomRequests(userId, otherUserId).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> println(it.message ?: "Something went wrong") + Status.LOADING -> { + + } + + Status.SUCCESS -> { + + loadDataData(viewLifecycleOwner, baasViewModel, userId!!, otherUserID.toInt(), adapterData) + } + } + } + } + + } + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/ChatUiFragmentXML.tsx b/src/components/builder/OtherUI/layout/ChatUiFragmentXML.tsx new file mode 100644 index 0000000..509f31a --- /dev/null +++ b/src/components/builder/OtherUI/layout/ChatUiFragmentXML.tsx @@ -0,0 +1,18 @@ +export default (configuration) => { + return ` + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/FriendListXmL.tsx b/src/components/builder/OtherUI/layout/FriendListXmL.tsx new file mode 100644 index 0000000..e94c032 --- /dev/null +++ b/src/components/builder/OtherUI/layout/FriendListXmL.tsx @@ -0,0 +1,25 @@ +export default (configuration) => { + return ` + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/ItemBroadcastVideoXML.tsx b/src/components/builder/OtherUI/layout/ItemBroadcastVideoXML.tsx new file mode 100644 index 0000000..e2f85d2 --- /dev/null +++ b/src/components/builder/OtherUI/layout/ItemBroadcastVideoXML.tsx @@ -0,0 +1,74 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/ReceiveImageMessageItemXML.tsx b/src/components/builder/OtherUI/layout/ReceiveImageMessageItemXML.tsx new file mode 100644 index 0000000..91b0191 --- /dev/null +++ b/src/components/builder/OtherUI/layout/ReceiveImageMessageItemXML.tsx @@ -0,0 +1,63 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/ReceiveTextMessageItemXML.tsx b/src/components/builder/OtherUI/layout/ReceiveTextMessageItemXML.tsx new file mode 100644 index 0000000..e4313b6 --- /dev/null +++ b/src/components/builder/OtherUI/layout/ReceiveTextMessageItemXML.tsx @@ -0,0 +1,58 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/ReceiveVideoMessageItemXML.tsx b/src/components/builder/OtherUI/layout/ReceiveVideoMessageItemXML.tsx new file mode 100644 index 0000000..37310d1 --- /dev/null +++ b/src/components/builder/OtherUI/layout/ReceiveVideoMessageItemXML.tsx @@ -0,0 +1,83 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/RoomDataXML.tsx b/src/components/builder/OtherUI/layout/RoomDataXML.tsx new file mode 100644 index 0000000..cb53a20 --- /dev/null +++ b/src/components/builder/OtherUI/layout/RoomDataXML.tsx @@ -0,0 +1,34 @@ +export default (configuration) => { + return ` + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/RoomListXML.tsx b/src/components/builder/OtherUI/layout/RoomListXML.tsx new file mode 100644 index 0000000..c4986bf --- /dev/null +++ b/src/components/builder/OtherUI/layout/RoomListXML.tsx @@ -0,0 +1,36 @@ +export default (configuration) => { + return ` + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/SendImageMessageItemXML.tsx b/src/components/builder/OtherUI/layout/SendImageMessageItemXML.tsx new file mode 100644 index 0000000..be1a08e --- /dev/null +++ b/src/components/builder/OtherUI/layout/SendImageMessageItemXML.tsx @@ -0,0 +1,45 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + +`; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/SendTextMessageItemXML.tsx b/src/components/builder/OtherUI/layout/SendTextMessageItemXML.tsx new file mode 100644 index 0000000..367e3be --- /dev/null +++ b/src/components/builder/OtherUI/layout/SendTextMessageItemXML.tsx @@ -0,0 +1,37 @@ +export default (configuration) => { + return ` + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/SendVideoMessageItemXML.tsx b/src/components/builder/OtherUI/layout/SendVideoMessageItemXML.tsx new file mode 100644 index 0000000..dafecf9 --- /dev/null +++ b/src/components/builder/OtherUI/layout/SendVideoMessageItemXML.tsx @@ -0,0 +1,63 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/SimpleChatViewWidgetXML.tsx b/src/components/builder/OtherUI/layout/SimpleChatViewWidgetXML.tsx new file mode 100644 index 0000000..91c6cae --- /dev/null +++ b/src/components/builder/OtherUI/layout/SimpleChatViewWidgetXML.tsx @@ -0,0 +1,115 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/layout/UserData.tsx b/src/components/builder/OtherUI/layout/UserData.tsx new file mode 100644 index 0000000..cb53a20 --- /dev/null +++ b/src/components/builder/OtherUI/layout/UserData.tsx @@ -0,0 +1,34 @@ +export default (configuration) => { + return ` + + + + + + + + + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/ChatRequestModel.tsx b/src/components/builder/OtherUI/model/ChatRequestModel.tsx new file mode 100644 index 0000000..a6dd93b --- /dev/null +++ b/src/components/builder/OtherUI/model/ChatRequestModel.tsx @@ -0,0 +1,47 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + + data class ChatRequest( + val room_id: String?, + ) + + data class ChatTextRequest( + val room_id: String?, + val user_id: Int?, + val message: String?, + ) + + data class ChatTextResponse( + val error: String?, + val message: String + ) + + data class ChatBotRequest( + val prompt: List?, + ) + + data class ChatBotTextRequest( + val role: String?, + val content: String? + ) + + + data class ChatBotTextResponse( + val error: Boolean?, + // val message: String, + val message: List? + ) + + data class ChatBotMessageListResponse( + val index: Int?, + val message: ChatBotMessageObjectResponse? + ) + + data class ChatBotMessageObjectResponse( + val role: String?, + val content: String + ) + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/ChatResponseModel.tsx b/src/components/builder/OtherUI/model/ChatResponseModel.tsx new file mode 100644 index 0000000..36ff511 --- /dev/null +++ b/src/components/builder/OtherUI/model/ChatResponseModel.tsx @@ -0,0 +1,34 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + + data class ChatResponse( + val error: String?, + val model: ArrayList + ) + + + data class SingleChatResponse( + val id: Int?, + val room_id: Int?, + val unread: Int?, + val create_at: String?, + val update_at: String?, + var view_type: Int?, + val chat: SingleChatMessageResponse?, + ) + + + + data class SingleChatMessageResponse( + val message: String?, + val user_id: Int?, + val is_image: Boolean?, + var timestamp: Long?, + var role: String? = null + // var role: String? + //val thread: String?, + ) + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/ChatRoomResnponseModel.tsx b/src/components/builder/OtherUI/model/ChatRoomResnponseModel.tsx new file mode 100644 index 0000000..7125855 --- /dev/null +++ b/src/components/builder/OtherUI/model/ChatRoomResnponseModel.tsx @@ -0,0 +1,22 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + data class ChatRoomResponse( + val list: ArrayList + ) + + + data class ChatRoomListResponse( + val id: Int?, + val user_id: Int?, + val other_user_id: Int?, + val chat_id: Int?, + val unread: Int?, + val create_at: String, + val update_at: String, + val user_update_at: String, + val other_user_update_at: String, + ) + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/CreateRoomRequests.tsx b/src/components/builder/OtherUI/model/CreateRoomRequests.tsx new file mode 100644 index 0000000..3715123 --- /dev/null +++ b/src/components/builder/OtherUI/model/CreateRoomRequests.tsx @@ -0,0 +1,10 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + data class CreateRoomRequests ( + val user_id: Int?, + val other_user_id: Int? + ) + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/FriendListResponse.tsx b/src/components/builder/OtherUI/model/FriendListResponse.tsx new file mode 100644 index 0000000..21b360a --- /dev/null +++ b/src/components/builder/OtherUI/model/FriendListResponse.tsx @@ -0,0 +1,12 @@ +export default (configuration) => { + return `package com.manaknight.app.model.remote + + + data class FriendListResponse( + val error: String?, + val list: ArrayList + ) + + + `; + }; \ No newline at end of file diff --git a/src/components/builder/OtherUI/model/GetVideoListResponse.tsx b/src/components/builder/OtherUI/model/GetVideoListResponse.tsx new file mode 100644 index 0000000..2dc9a40 --- /dev/null +++ b/src/components/builder/OtherUI/model/GetVideoListResponse.tsx @@ -0,0 +1,12 @@ +export default (configuration) => { + return `package ${configuration.packageName}.model.remote + + data class GetVideoListResponse( + val error: Boolean?, + val message: String?, + val title: String?, + val update_at: String?, + val price: String?, + ) + `; +}; \ No newline at end of file diff --git a/src/components/builder/OtherUI/otherUi.ts b/src/components/builder/OtherUI/otherUi.ts new file mode 100644 index 0000000..bf59df7 --- /dev/null +++ b/src/components/builder/OtherUI/otherUi.ts @@ -0,0 +1,239 @@ +import ChatMessage from "../model/ChatMessage"; +import SimpleChatView from "../widget/SimpleChatView"; +import ChatRoomAdapter from "./adapter/ChatRoomAdapter"; +import FriendListAdapter from "./adapter/FriendListAdapter"; +import SimpleChatAdapter from "./adapter/SimpleChatAdapter"; +import VideosAdapter from "./adapter/VideosAdapter"; +import ChatRoomRecyclerData from "./data/ChatRoomRecyclerData"; +import FriendListRecyclerData from "./data/FriendListRecyclerData"; +import FriendListFragment from "./fragment/FriendListFragment"; +import RoomListFragment from "./fragment/RoomListFragment"; +import FriendListXmL from "./layout/FriendListXmL"; +import ReceiveImageMessageItemXML from "./layout/ReceiveImageMessageItemXML"; +import ReceiveTextMessageItemXML from "./layout/ReceiveTextMessageItemXML"; +import ReceiveVideoMessageItemXML from "./layout/ReceiveVideoMessageItemXML"; +import RoomDataXML from "./layout/RoomDataXML"; +import RoomListXML from "./layout/RoomListXML"; +import SendImageMessageItemXML from "./layout/SendImageMessageItemXML"; +import SendTextMessageItemXML from "./layout/SendTextMessageItemXML"; +import SendVideoMessageItemXML from "./layout/SendVideoMessageItemXML"; +import SimpleChatViewWidgetXML from "./layout/SimpleChatViewWidgetXML"; +import ItemBroadcastVideoXML from "./layout/ItemBroadcastVideoXML"; +import UserData from "./layout/UserData"; +import ChatRequestModel from "./model/ChatRequestModel"; +import ChatResponseModel from "./model/ChatResponseModel"; +import ChatRoomResnponseModel from "./model/ChatRoomResnponseModel"; +import CreateRoomRequests from "./model/CreateRoomRequests"; +import FriendListResponse from "./model/FriendListResponse"; +import GetVideoListResponse from "./model/GetVideoListResponse"; + +export function findComponents(data, result = []) { + if (!Array.isArray(data)) data = [data]; + for (const item of data) { + if ("components" in item) { + findComponents(item.components, result); + } + if ("children" in item) { + findComponents(item.children, result); + } + if ("props" in item && item.name == "ChatUi") { + result.push(item); + } + } + return result; +} + +export const generateOtherUI = (configuration) => { + let copyList = []; + + // .........CHATUI COMPONENTS STARTS............... + const chatComp = (configuration) => { + if (findComponents(configuration.fragment).length == 0) { + return ""; + } else { + //Data + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/data/ChatRoomRecyclerData.kt", + content: ChatRoomRecyclerData(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/data/FriendListRecyclerData.kt", + content: FriendListRecyclerData(configuration), + }); + //Adapters + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/adapters/ChatRoomAdapter.kt", + content: ChatRoomAdapter(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/adapters/FriendListAdapter.kt", + content: FriendListAdapter(configuration), + }); + + // UI + // Fragments; + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/ui/fragments/chatui/FriendListFragment.kt", + content: FriendListFragment(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/ui/fragments/chatui/RoomListFragment.kt", + content: RoomListFragment(configuration), + }); + + // .........CHATUI COMPONENTS ENDS............... + } + }; + chatComp(configuration); + + // Models needs to be exported for the apiserve and apirepository + // Model + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/" + + "ChatMessage.kt", + content: ChatMessage(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/ChatRequest.kt", + content: ChatRequestModel(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/ChatResponse.kt", + content: ChatResponseModel(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/ChatRoomResponse.kt", + content: ChatRoomResnponseModel(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/FriendListResponse.kt", + content: FriendListResponse(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/GetVideoListResponse.kt", + content: GetVideoListResponse(configuration), + }); + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/CreateRoomRequests.kt", + content: CreateRoomRequests(configuration), + }); + + //widget + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/widget/SimpleChatView.kt", + content: SimpleChatView(configuration), + }); + + //Layouts + + copyList.push({ + fileName: "app/src/main/res/layout/simple_chat_view_widget.xml", + content: SimpleChatViewWidgetXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/send_video_message_item.xml", + content: SendVideoMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/send_text_message_item.xml", + content: SendTextMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/send_image_message_item.xml", + content: SendImageMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/receive_video_message_item.xml", + content: ReceiveVideoMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/receive_text_message_item.xml", + content: ReceiveTextMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/receive_image_message_item.xml", + content: ReceiveImageMessageItemXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/room_data.xml", + content: RoomDataXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/fragment_room_list.xml", + content: RoomListXML(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/user_data.xml", + content: UserData(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/fragment_friend_list.xml", + content: FriendListXmL(configuration), + }); + copyList.push({ + fileName: "app/src/main/res/layout/item_broadcast_video.xml", + content: ItemBroadcastVideoXML(configuration), + }); + + // Ui Adapters + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/ui/adapter/SimpleChatAdapter.kt", + content: SimpleChatAdapter(configuration), + }); + + //Adapters + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/adapters/VideosAdapter.kt", + content: VideosAdapter(configuration), + }); + + return copyList; +}; diff --git a/src/components/builder/OtherUI/repositories/ChatRepositories.tsx b/src/components/builder/OtherUI/repositories/ChatRepositories.tsx new file mode 100644 index 0000000..8752311 --- /dev/null +++ b/src/components/builder/OtherUI/repositories/ChatRepositories.tsx @@ -0,0 +1,62 @@ +export default (configuration) => { + return ` + fun getAllUser( ): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.getAllUser() + emit(response) + } + + fun sendMessageToBot( request: String): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.sendMessageToBot(request) + emit(response) + } + + fun sendMessageToBot( request: ChatBotRequest): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.sendMessageToBot(request) + emit(response) + } + + fun sendTextMessage( request: ChatTextRequest): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.sendTextMessage(request) + emit(response) + } + + fun createRoomRequests( request: CreateRoomRequests): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.createRoomRequests(request) + emit(response) + } + + +fun getChats( request: ChatRequest): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.getChats(request) + emit(response) + } + + +fun getStartPool( user_id: Int): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.getStartPool(user_id) + emit(response) + } + +fun getAllRoom( user_id: Int): LiveData> = + liveData(Dispatchers.IO) { + emit(Resource.loading(null)) + val response = remoteDataSource.getAllRoom(user_id) + emit(response) + } + + `; + }; \ No newline at end of file diff --git a/src/components/builder/ReactBuilder.tsx b/src/components/builder/ReactBuilder.tsx new file mode 100644 index 0000000..f8ca56b --- /dev/null +++ b/src/components/builder/ReactBuilder.tsx @@ -0,0 +1,2 @@ +const ReactBuilder = (props) => {}; +export default ReactBuilder; diff --git a/src/components/builder/SwiftBuilder.tsx b/src/components/builder/SwiftBuilder.tsx new file mode 100644 index 0000000..c55ca80 --- /dev/null +++ b/src/components/builder/SwiftBuilder.tsx @@ -0,0 +1,3 @@ +const SwiftBuilder = (props) => {}; +export default SwiftBuilder; +screen \ No newline at end of file diff --git a/src/components/builder/alerts/Adapter.tsx b/src/components/builder/alerts/Adapter.tsx new file mode 100644 index 0000000..bbdf0d8 --- /dev/null +++ b/src/components/builder/alerts/Adapter.tsx @@ -0,0 +1,61 @@ +export default (configuration) => { + return ` + + package ${configuration.packageName}.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import ${configuration.name}.R +import ${configuration.name}.databinding.ItemAppAlertBinding +import ${configuration.packageName}.extensions.getTimeInAgo +import ${configuration.packageName}.extensions.loadImageFromUrl +import ${configuration.packageName}.extensions.setOnClickWithDebounce +import ${configuration.packageName}.model.remote.AlertModel + + +class AlertsAdapter( + val onClick: (AlertModel) -> Unit +) : + RecyclerView.Adapter() { + + private val list: ArrayList = ArrayList() + + inner class ViewHolder(val binding: ItemAppAlertBinding) : + RecyclerView.ViewHolder(binding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val itemView = + ItemAppAlertBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(itemView) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val model = list[position] + println(model) + with(holder.binding) { + textViewAlertMsg.text = model.message + tvTimeAgo.text = model.update_at.getTimeInAgo() + imageView4.loadImageFromUrl(model.image) + root.setOnClickWithDebounce { + onClick(model) + } + } + + } + + override fun getItemCount(): Int { + return list.size + } + + fun refresh(newList: ArrayList) { + list.clear() + list.addAll(newList) + notifyDataSetChanged() + } + + +} + + ` +} \ No newline at end of file diff --git a/src/components/builder/alerts/AdapterItemXML.tsx b/src/components/builder/alerts/AdapterItemXML.tsx new file mode 100644 index 0000000..6bc2b60 --- /dev/null +++ b/src/components/builder/alerts/AdapterItemXML.tsx @@ -0,0 +1,59 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + ` +} \ No newline at end of file diff --git a/src/components/builder/alerts/DialogXML.tsx b/src/components/builder/alerts/DialogXML.tsx new file mode 100644 index 0000000..f111477 --- /dev/null +++ b/src/components/builder/alerts/DialogXML.tsx @@ -0,0 +1,69 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + + + + + ` +} \ No newline at end of file diff --git a/src/components/builder/alerts/Fragment.tsx b/src/components/builder/alerts/Fragment.tsx new file mode 100644 index 0000000..4cbea53 --- /dev/null +++ b/src/components/builder/alerts/Fragment.tsx @@ -0,0 +1,149 @@ +export default (configuration) => { + return ` + + package ${configuration.packageName}.ui.fragments.alerts + +import ${configuration.name}.R +import ${configuration.name}.databinding.FragmentAlertsBinding +import android.app.AlertDialog +import android.content.ContentValues.TAG +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import ${configuration.packageName}.data.local.AppPreferences +import ${configuration.packageName}.model.remote.AlertModel +import ${configuration.packageName}.adapter.AlertsAdapter +import ${configuration.packageName}.extensions.* +import ${configuration.name}.databinding.DialogAlertViewBinding +import ${configuration.packageName}.extensions.hide +import ${configuration.packageName}.extensions.loadImageFromUrl +import ${configuration.packageName}.extensions.setOnClickWithDebounce +import ${configuration.packageName}.extensions.setVerticalLayout +import ${configuration.packageName}.extensions.show +import ${configuration.packageName}.extensions.snackBar +import ${configuration.packageName}.extensions.viewBinding +import ${configuration.packageName}.network.Status +import ${configuration.packageName}.viewmodels.BaasViewModel +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.viewModel + + + +class AlertsFragment : Fragment(R.layout.fragment_alerts) { + + private val viewModel: BaasViewModel by viewModel() + private val binding by viewBinding(FragmentAlertsBinding::bind) + private val newAlerts: ArrayList = ArrayList() + private val readAlerts: ArrayList = ArrayList() + private val newAlertsAdapter by lazy { AlertsAdapter(this::onAlertClick) } + private val pref by inject() + + private fun onAlertClick(item: AlertModel) { + Log.d(TAG, "onAlertClick: $item") + showDialog(item.message, item.id) + } + + private fun showDialog(message: String, id: Int) { + val builder = AlertDialog.Builder(requireContext()) + val binding = DialogAlertViewBinding.inflate(layoutInflater) + val dialog = builder.create() + + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + + binding.tvAlertDialogMsg.text = message + + binding.buttonAlertDialogClose.setOnClickWithDebounce { + dialog.dismiss() + setAlertSeen(id) + } + + dialog.setView(binding.root) + dialog.setCancelable(true) + dialog.show() + } + + + + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + + binding.rcvNewAlerts.apply { + setVerticalLayout() + adapter = newAlertsAdapter + } + + + } + + override fun onResume() { + super.onResume() + getAlerts() + } + + private fun getAlerts() { + viewModel.appAlertsList("id,desc", "1,20", "is_read,eq,0").observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong)) + Status.LOADING -> {} + Status.SUCCESS -> { + var alerts: List? = it.data?.list?.map { map -> + val id = map["id"]?.toString()?.toDoubleOrNull()?.toInt() ?: 0 + val create_at = map["create_at"] as? String ?: "" + val image = map["image"] as? String ?: "" + val is_read = map["is_read"]?.toString()?.toDoubleOrNull()?.toInt() ?: 1 + val message = map["message"] as? String ?: "" + val update_at = map["update_at"] as? String ?: "" + val user_id = map["user_id"]?.toString()?.toDoubleOrNull()?.toInt() ?: 0 + AlertModel(id, user_id, image, is_read, message, create_at, update_at ) + } + setAlertLists(alerts) + + } + } + } + } + + private fun setAlertSeen(id: Int = 0) { + viewModel.appAlertsUpdate(1, id.toString()).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong)) + Status.LOADING -> {} + Status.SUCCESS -> { + + setAlertLists(newAlerts.filterNot { alert -> alert.id == id }) + } + } + } + } + + private fun setAlertLists(message: List?) { + newAlerts.clear() + newAlerts.addAll(message?.filter { it.is_read == 0 } ?: ArrayList()) + newAlertsAdapter.refresh(newAlerts) + + + if (newAlerts.isEmpty()) { + binding.tvTagNew.hide() + binding.rcvNewAlerts.hide() + } else { + binding.tvTagNew.show() + binding.rcvNewAlerts.show() + } + + if (newAlerts.isEmpty() ) { + binding.llNoAlerts.show() + } + } + +} + +` +} \ No newline at end of file diff --git a/src/components/builder/alerts/FragmentXML.tsx b/src/components/builder/alerts/FragmentXML.tsx new file mode 100644 index 0000000..a941d3d --- /dev/null +++ b/src/components/builder/alerts/FragmentXML.tsx @@ -0,0 +1,102 @@ +export default (configuration) => { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + ` +} \ No newline at end of file diff --git a/src/components/builder/alerts/Model.tsx b/src/components/builder/alerts/Model.tsx new file mode 100644 index 0000000..da94ab9 --- /dev/null +++ b/src/components/builder/alerts/Model.tsx @@ -0,0 +1,17 @@ +export default (configuration) => { + return ` + package ${configuration.packageName}.model.remote + + data class AlertModel( + val id: Int, + val user_id: Int, + val image: String, + val is_read: Int, + val message: String, + val create_at: String, + val update_at: String, + + ) + + ` +} \ No newline at end of file diff --git a/src/components/builder/alerts/alerts.ts b/src/components/builder/alerts/alerts.ts new file mode 100644 index 0000000..97e2e33 --- /dev/null +++ b/src/components/builder/alerts/alerts.ts @@ -0,0 +1,61 @@ +import Adapter from "./Adapter" +import AdapterItemXML from "./AdapterItemXML" +import DialogXML from "./DialogXML" +import FragmentXML from "./FragmentXML" +import Model from "./Model" +import Fragment from "./Fragment" + + + +export const generateAlertUI = (configuration) => { + let copyList = [] + + //Fragments + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/ui/fragments/alerts/AlertsFragment.kt", + content: Fragment(configuration) + }) + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/adapters/AlertsAdapter.kt", + content: Adapter(configuration) + }) + + copyList.push({ + fileName: + "app/src/main/java/com/" + + configuration.name.toLowerCase() + + "/app/model/remote/AlertModel.kt", + content: Model(configuration) + }) + + //Layouts + copyList.push({ + fileName: + "app/src/main/res/layout/fragment_alerts.xml", + content: FragmentXML(configuration) + }) + + copyList.push({ + fileName: + "app/src/main/res/layout/dialog_alert_view.xml", + content: DialogXML(configuration) + }) + + copyList.push({ + fileName: + "app/src/main/res/layout/item_app_alert.xml", + content: AdapterItemXML(configuration) + }) + + + + + return copyList; +} \ No newline at end of file diff --git a/src/components/builder/androidUtils/SimpleChatUtil.tsx b/src/components/builder/androidUtils/SimpleChatUtil.tsx new file mode 100644 index 0000000..adc3ae5 --- /dev/null +++ b/src/components/builder/androidUtils/SimpleChatUtil.tsx @@ -0,0 +1,56 @@ +export default (configuration) => { + + + return ` + package ${configuration.packageName}.utils + + + class SimpleChatUtil { + + companion object{ + private const val secondMillis = 1000 + private const val minuteMillis = 60 * secondMillis + private const val hourMillis = 60 * minuteMillis + private const val daysMillis = 24 * hourMillis + + fun getTimeAgo(timeStamp: Long): CharSequence? { + var time = timeStamp + if (time < 1000000000000L) { + time *= 1000 + } + + val now = System.currentTimeMillis() + if (time > now || time <= 0) { + return null + } + + val diff: Long = now - time + return when { + diff < minuteMillis -> { + "just now" + } + diff < 2 * minuteMillis -> { + "1 min ago" + } + diff < 50 * minuteMillis -> { + " " + diff / minuteMillis + " min ago" + } + diff < 90 * minuteMillis -> { + "1 hr ago" + } + diff < 24 * hourMillis -> { + " " + diff / hourMillis + " hr ago" + } + diff < 48 * hourMillis -> { + "yesterday" + } + else -> { + " " + diff / daysMillis + " d ago" + } + } + } + + } + } + ` +} \ No newline at end of file diff --git a/src/components/builder/auth/ForgetPasswordFragment.tsx b/src/components/builder/auth/ForgetPasswordFragment.tsx new file mode 100644 index 0000000..b451e50 --- /dev/null +++ b/src/components/builder/auth/ForgetPasswordFragment.tsx @@ -0,0 +1,77 @@ +export const ForgetPasswordFragment = (configuration) => { + return ` + package ${configuration.packageName}.ui.fragments + + import android.os.Bundle + import android.view.View + import androidx.core.widget.doAfterTextChanged + import androidx.fragment.app.Fragment + import androidx.navigation.fragment.findNavController + import ${configuration.name}.R + import ${configuration.packageName}.data.local.AppPreferences + import ${configuration.name}.databinding.FragmentForgetPasswordBinding + import ${configuration.packageName}.extensions.setOnClickWithDebounce + import ${configuration.packageName}.extensions.snackBar + import ${configuration.packageName}.extensions.viewBinding + import ${configuration.packageName}.network.Status + import ${configuration.packageName}.viewmodels.BaasViewModel + import ${configuration.packageName}.extensions.hideSoftKeyboard + import org.koin.android.ext.android.inject + import org.koin.androidx.viewmodel.ext.android.viewModel + import android.widget.VideoView + import androidx.activity.result.contract.ActivityResultContracts + import com.manaknight.app.extensions.viewBinding + import android.provider.MediaStore + import android.widget.Toast + import androidx.appcompat.app.AppCompatActivity + + + +class ForgetPasswordFragment : Fragment(R.layout.fragment_forget_password) { + + private val binding by viewBinding(FragmentForgetPasswordBinding::bind) + private val baasViewModel: BaasViewModel by viewModel() + var email = "" + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.forgetPassword.doAfterTextChanged { email = it.toString() } + + binding.continueButton.setOnClickListener { + + if (email.isEmpty()) { + Toast.makeText(context, "Please enter email address.", Toast.LENGTH_SHORT).show(); + } else { + requireActivity().hideSoftKeyboard() + baasViewModel.forgotPasswordMobile(email).observe(viewLifecycleOwner) { + when (it.status) { + Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong)) + Status.LOADING -> { + snackBar("Loading") + } + + Status.SUCCESS -> { + snackBar("Reset code sent to email") + + findNavController().navigate(R.id.resetPasswordFragment) + } + } + } + } + } + + } + + override fun onResume() { + super.onResume() + // (activity as AppCompatActivity?)!!.supportActionBar!!.hide() + } + + override fun onStop() { + super.onStop() + // (activity as AppCompatActivity?)!!.supportActionBar!!.show() + } + +} + `; +}; diff --git a/src/components/builder/auth/ForgetPasswordFragmentXML.tsx b/src/components/builder/auth/ForgetPasswordFragmentXML.tsx new file mode 100644 index 0000000..e542d20 --- /dev/null +++ b/src/components/builder/auth/ForgetPasswordFragmentXML.tsx @@ -0,0 +1,51 @@ +export const ForgetPasswordFragmentXML = (configuration) => { + return ` + + + + + + + + + + + +
    + {error && ( +
    + {error + " Please try again later!"} +
    + )} + {room && ( +
    +
    + +
    + {audio && video && ( +
    + +
    + )} + +
    + )} + + ); +} + +export default Video; diff --git a/src/components/video/videoItem.tsx b/src/components/video/videoItem.tsx new file mode 100644 index 0000000..10665a9 --- /dev/null +++ b/src/components/video/videoItem.tsx @@ -0,0 +1,29 @@ + +import { useRef, useEffect } from "react"; + +function VideoItem({ videoStream, audioStream, muted }) { + const videoRef = useRef(null); + const audioRef = useRef(null); + + useEffect(() => { + videoRef.current && videoStream?.attach(videoRef.current); + audioRef.current && audioStream?.attach(audioRef.current); + }, [videoStream, audioStream]); + + return ( + <> + + + + ); +} + +export default VideoItem; diff --git a/src/configuration.ts b/src/configuration.ts new file mode 100644 index 0000000..9443b15 --- /dev/null +++ b/src/configuration.ts @@ -0,0 +1,93 @@ +export const config = +{ + options: { + use_google_login: true, + use_facebook_login: true, + nav: "horizontal", //horizontal|vertical + use_2fa: true, + use_ssr: true, + use_captcha: true, + }, + pages: [ + { + type: "add", // list|view|edit|add|custom + role: "admin", + model: "user", + route: "admin/add-user", + columns: [ + { "name": "email", type: "string", "mapping": {}, "rules": {} }, + { "name": "f_name", type: "string", "mapping": {}, "rules": {} }, + { "name": "l_name", type: "string", "mapping": {}, "rules": {} }, + { "name": "password", type: "string", "mapping": {}, "rules": {} } + ], + + }, + { + type: "edit", // list|view|edit|add|custom + role: "admin", + model: "user", + route: "admin/edit-user/:id", + columns: [ + { "name": "email", type: "string", "mapping": {}, "rules": {} }, + { "name": "f_name", type: "select", "mapping": {}, "rules": {}, populate: "user" }, + { "name": "l_name", type: "string", "mapping": {}, "rules": {} }, + { "name": "password", type: "string", "mapping": {}, "rules": {} } + ], + + }, + { + type: "view", // list|view|edit|add|custom + role: "admin", + model: "user", + route: "admin/view-user/:id", + columns: [ + { "name": "email", type: "string", "mapping": {} }, + { "name": "user_id", type: "select", "mapping": {}, join: {model: "", column: ""} }, + { "name": "l_name", type: "string", "mapping": {} }, + { "name": "password", type: "string", "mapping": {}, "rules": {} } + + ], + + }, + { + type: "list", // list|view|edit|add|custom + role: "admin", + model: "user", + route: "admin/user", + columns: [ + { "name": "email", type: "string", "mapping": {}, is_filter: true }, + { "name": "user_id", type: "select", "mapping": {}, join: "user|name" }, + { "name": "l_name", type: "string", "mapping": {} }, + { "name": "password", type: "string", "mapping": {}, "rules": {} } + ], + + }, + { + type: "custom", // list|view|edit|add|custom + role: "public", //admin|nanny|customer|public + model: "user", + title: "About", + route: "/about", + components: [ + { + id: 9890, //Add button, + name: "AddButton", + props: { + model: "", + role: "" + } + }, + { + id: 98098, + } + ] + + + }, + + ] +} + + + + diff --git a/src/context/Auth/AuthContext.tsx b/src/context/Auth/AuthContext.tsx new file mode 100644 index 0000000..c71c4ee --- /dev/null +++ b/src/context/Auth/AuthContext.tsx @@ -0,0 +1,136 @@ +import React, { useReducer, useEffect } from "react"; +import { AuthState, AuthAction, AuthContextType, UserDetails } from "./types"; +import { RoleMap, updatedRolesFn } from "@/utils/utils"; +import { useSDK } from "@/hooks/useSDK"; +import { RoleEnum } from "@/utils/Enums"; + +const initialState: AuthState = { + isAuthenticated: false, + user: null, + userDetails: { + firstName: null, + lastName: null, + photo: null, + }, + token: null, + role: null, + sessionExpired: null, +}; + +export const AuthContext = React.createContext({ + ...initialState, + dispatch: () => null, +}); + +const reducer = (state: AuthState, action: AuthAction): AuthState => { + switch (action.type) { + case "LOGIN": { + const { user_id, token, role, first_name, last_name, photo } = + action.payload; + localStorage.setItem("user", user_id); + localStorage.setItem("token", token); + localStorage.setItem("role", role); + + const userDetails: UserDetails = { + firstName: first_name ?? null, + lastName: last_name ?? null, + photo: photo ?? null, + }; + + return { + ...state, + isAuthenticated: true, + user: Number(user_id), + token, + role, + userDetails, + }; + } + case "UPDATE_PROFILE": + return { + ...state, + role: localStorage.getItem("role"), + profile: action.payload, + }; + case "LOGOUT": + localStorage.removeItem("user"); + localStorage.removeItem("token"); + localStorage.removeItem("role"); + return { + ...initialState, + }; + case "SESSION_EXPIRED": + return { + ...state, + sessionExpired: action.payload, + }; + default: + return state; + } +}; + +export const tokenExpireError = ( + dispatch: React.Dispatch, + errorMessage: string +): void => { + const role = localStorage.getItem("role"); + if (errorMessage === "TOKEN_EXPIRED") { + dispatch({ type: "SESSION_EXPIRED", payload: true }); + } +}; + +interface AuthProviderProps { + children: React.ReactNode; +} + +const AuthProvider: React.FC = ({ children }) => { + const { sdk } = useSDK(); + + const [state, dispatch] = useReducer(reducer, initialState); + + const checkToken = async (token: string, user: string, role: RoleEnum) => { + try { + const res = await sdk.getProfile(role); + + if (res.error) { + throw new Error(res.message); + } + + dispatch({ + type: "LOGIN", + payload: { + user_id: user, + token, + role, + }, + }); + } catch (error) { + dispatch({ type: "LOGOUT" }); + const updatedRole = updatedRolesFn(role, window.location); + + if (updatedRole) { + window.location.href = `/${updatedRole}/login`; + } else { + window.location.href = "/"; + } + } + }; + + useEffect(() => { + const user = localStorage.getItem("user"); + const token = localStorage.getItem("token"); + const role = localStorage.getItem("role") as RoleEnum; + + if (token && user && role) { + checkToken(token, user, role as RoleEnum); + } + }, []); + + return ( + + {children} + + ); +}; + +export default AuthProvider; diff --git a/src/context/Auth/index.ts b/src/context/Auth/index.ts new file mode 100644 index 0000000..8312952 --- /dev/null +++ b/src/context/Auth/index.ts @@ -0,0 +1,2 @@ +export { default as AuthProvider, AuthContext, tokenExpireError } from "./AuthContext"; +export type { AuthState, AuthAction, AuthContextType, UserDetails } from "./types"; diff --git a/src/context/Auth/types.ts b/src/context/Auth/types.ts new file mode 100644 index 0000000..be59f09 --- /dev/null +++ b/src/context/Auth/types.ts @@ -0,0 +1,26 @@ +export interface UserDetails { + firstName: string | null; + lastName: string | null; + photo: string | null; +} + +export interface AuthState { + isAuthenticated: boolean; + user: number | null; + userDetails: UserDetails; + token: string | null; + role: string | null; + sessionExpired: boolean | null; + profile?: Record; +} + +export type AuthAction = + | { type: "LOGIN"; payload: { user_id: string; token: string; role: string; first_name?: string; last_name?: string; photo?: string } } + | { type: "UPDATE_PROFILE"; payload: Record } + | { type: "LOGOUT" } + | { type: "SESSION_EXPIRED"; payload: boolean }; + +export interface AuthContextType extends AuthState { + dispatch: React.Dispatch; + state: AuthState +} diff --git a/src/context/Global/GlobalActions.ts b/src/context/Global/GlobalActions.ts new file mode 100644 index 0000000..56ca1d9 --- /dev/null +++ b/src/context/Global/GlobalActions.ts @@ -0,0 +1,674 @@ +import { Dispatch } from "react"; +import { tokenExpireError } from "@/context/Auth"; +import TreeSDK from "@/utils/TreeSDK"; +import MkdSDK from "@/utils/MkdSDK"; +import { ApiError, GlobalAction } from "./types"; + +import { + REQUEST_FAILED, + REQUEST_LOADING, + REQUEST_SUCCESS, + RequestItems, + SET_GLOBAL_PROPERTY, +} from "./GlobalConstants"; +import { showToast } from "./GlobalContext"; +import { RestAPIMethod } from "@/utils/types/types"; + +export const setGLobalProperty = ( + dispatch: Dispatch, + data: any, + property: string +): void => { + dispatch({ + property, + type: SET_GLOBAL_PROPERTY, + payload: data, + }); +}; + +export function setLoading( + dispatch: Dispatch, + data: boolean, + item: string, + where?: string +): void { + dispatch({ + item, + type: REQUEST_LOADING, + payload: data, + }); +} + +export const dataSuccess = ( + dispatch: Dispatch, + data: any, + item: string +): void => { + dispatch({ + item, + type: REQUEST_SUCCESS, + payload: data, + }); +}; + +export const dataFailure = ( + dispatch: Dispatch, + data: any, + item: string +): void => { + dispatch({ + item, + type: REQUEST_FAILED, + payload: data, + }); +}; + +export interface ReadImageUrlResult { + error: boolean; + data?: string; + imageBlob?: Blob; + message?: string; +} + +export const readImageUrl = ( + url: string, + cb: (result: ReadImageUrlResult) => void +): void => { + const xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + + xhr.onload = function () { + if (![401, 402, 403, 404, 500, 502, 501].includes(xhr.status)) { + const arrayBuffer = xhr.response; + const blob = new Blob([arrayBuffer], { type: "image/png" }); + const reader = new FileReader(); + reader.onloadend = function () { + cb({ error: false, data: reader.result as string, imageBlob: blob }); + }; + reader.readAsDataURL(blob); + } else { + const errorMessage = `Request failed. Status: ${xhr.status}`; + console.error(errorMessage); + cb({ error: true, message: errorMessage }); + } + }; + + xhr.onerror = function () { + const errorMessage = "An error occurred during the request."; + console.error(errorMessage); + }; + + xhr.send(); +}; + +export interface GetSingleModelOptions { + method?: RestAPIMethod; + join?: string | null; + allowToast?: boolean; + state?: string; + isPublic?: boolean; + role: string; +} + +export interface GetSingleModelResult { + error: boolean; + data?: any; + message: string; +} + +export const getSingleModel = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + id: number | string, + options: GetSingleModelOptions = { + method: "GET", + join: null, + allowToast: true, + state: RequestItems?.viewModel, + isPublic: false, + role: "", + } +): Promise => { + const sdk = new MkdSDK(); + const state = options?.state ?? RequestItems.viewModel; + const method = options?.method ?? "GET"; + setLoading(globalDispatch, true, state); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + sdk.setTable(table.trim()); + const result = await sdk.callRestAPI( + { + id: Number(id), + ...{ ...(options?.join ? { join: options?.join } : null) }, + }, + method, + options?.role + ); + + if (!result?.error) { + dataSuccess(globalDispatch, { data: result?.model }, state); + } + setLoading(globalDispatch, false, state); + return { + error: false, + data: result?.model, + message: result?.message ?? "Success", + }; + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, state); + dataFailure(globalDispatch, { message, id }, state); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + if (!options?.isPublic) { + tokenExpireError(authDispatch, message); + } + return { error: true, message }; + } +}; + +export interface GetManyOptions { + filter?: string[]; + join?: string | null; + allowToast?: boolean; + role: string; +} + +export interface GetManyResult { + error: boolean; + data?: any[]; + message?: string; +} + +export const getMany = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + options: GetManyOptions = { + filter: [], + join: null, + allowToast: true, + role: "", + } +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, RequestItems?.listModel); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.getList(table, options?.role, { + ...{ + ...(options?.join ? { join: options?.join } : null), + ...(options?.filter && options?.filter?.length + ? { filter: options?.filter } + : null), + }, + }); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { data: result?.list }, + RequestItems?.listModel + ); + } + setLoading(globalDispatch, false, RequestItems?.listModel); + return { error: false, data: result?.list }; + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, RequestItems?.listModel); + dataFailure(globalDispatch, { message }, RequestItems?.listModel); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface GetManyByIdsResult { + error: boolean; + data?: any[]; + message?: string; +} + +export interface GetManyByIdsOptions { + join?: string | null; + allowToast?: boolean; + role: string; +} + +export const getManyByIds = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + ids: (number | string)[], + options: GetManyByIdsOptions = { + join: null, + allowToast: true, + role: "", + } +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, RequestItems?.listModel); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.getList(table, options?.role, { + ...{ + ...(options?.join ? { join: options?.join } : null), + filter: [`id,in,${ids.join(",")}`], + }, + }); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { data: result?.list }, + RequestItems?.listModel + ); + } + setLoading(globalDispatch, false, RequestItems?.listModel); + return { error: false, data: result?.list }; + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, RequestItems?.listModel); + dataFailure(globalDispatch, { message, ids }, RequestItems?.listModel); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface CreateRequestResult { + error: boolean; + data?: any; + message?: string; +} + +export interface CreateRequestOptions { + allowToast?: boolean; + role: string; +} + +export const createRequest = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + payload: any, + options: CreateRequestOptions = { + allowToast: true, + role: "", + } +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, RequestItems?.createModel); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.create(table, options?.role, payload); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { message: result?.message, data: result?.data }, + RequestItems?.createModel + ); + setLoading(globalDispatch, false, RequestItems?.createModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "Success", + 4000, + "success" + ); + } + return { error: false, data: result?.data, message: result?.message }; + } else { + setLoading(globalDispatch, false, RequestItems?.createModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "An error occurred", + 4000, + "error" + ); + } + return { error: true, message: result?.message }; + } + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, RequestItems?.createModel); + dataFailure(globalDispatch, { message }, RequestItems?.createModel); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface UpdateRequestResult { + error: boolean; + message?: string; +} + +export interface UpdateRequestOptions { + allowToast?: boolean; + role: string; +} + +export const updateRequest = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + id: number | string, + payload: any, + options: UpdateRequestOptions = { + allowToast: true, + role: "", + } +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, RequestItems?.updateModel); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.update(table, id, options?.role, payload); + + if (!result?.error) { + setLoading(globalDispatch, false, RequestItems?.updateModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "Success", + 4000, + "success" + ); + } + return { error: false }; + } else { + setLoading(globalDispatch, false, RequestItems?.updateModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "An error occurred", + 4000, + "error" + ); + } + return { error: true }; + } + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, RequestItems?.updateModel); + dataFailure(globalDispatch, { message }, RequestItems?.updateModel); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface DeleteRequestResult { + error: boolean; + data?: any; + message?: string; +} + +export interface DeleteRequestOptions { + allowToast?: boolean; + role: string; +} + +export const deleteRequest = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + id: number | string, + payload: any, + options: DeleteRequestOptions = { + allowToast: true, + role: "", + } +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, RequestItems?.deleteModel); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.delete(table, id, options?.role, payload); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { message: result?.message }, + RequestItems?.deleteModel + ); + setLoading(globalDispatch, false, RequestItems?.deleteModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "Success", + 4000, + "success" + ); + } + return { error: false, data: result?.data }; + } else { + setLoading(globalDispatch, false, RequestItems?.deleteModel); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "An error occurred", + 4000, + "error" + ); + } + return { error: true }; + } + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, RequestItems?.deleteModel); + dataFailure(globalDispatch, { message }, RequestItems?.deleteModel); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface GetListOptions { + filter?: string[]; + join?: string[]; + size?: number; + order?: string; + direction?: "desc" | "asc"; + role: string; +} + +export interface GetListResult { + error: boolean; + data?: any[]; + message?: string; +} + +export const getList = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + table: string, + options: GetListOptions, + state: string | undefined = undefined +): Promise => { + const tdk = new TreeSDK(); + setLoading(globalDispatch, true, state ?? table); + try { + if (!options?.role) { + throw new Error("role is required"); + } + + const result = await tdk.getList(table, options?.role, { + ...options, + }); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { message: result?.message, data: result?.list }, + state ?? table + ); + setLoading(globalDispatch, false, state ?? table); + return { error: false, data: result?.list }; + } else { + setLoading(globalDispatch, false, state ?? table); + return result; + } + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, state ?? table); + dataFailure(globalDispatch, { message }, state ?? table); + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export interface CustomRequestOptions { + endpoint: string; + payload?: any; + method?: RestAPIMethod; + signal?: AbortSignal | null | undefined; + allowToast?: boolean; +} + +export interface CustomRequestResult { + error: boolean; + data?: any; + message?: string; + validation?: any; +} + +export const customRequest = async ( + globalDispatch: Dispatch, + authDispatch: Dispatch, + options: CustomRequestOptions = { + allowToast: true, + endpoint: "", + payload: {}, + method: "GET", + signal: null, + }, + state: string = RequestItems.customRequest +): Promise => { + if (!options.endpoint) { + showToast( + globalDispatch, + "options.endpoint is a required field", + 4000, + "error" + ); + return { error: true }; + } + const sdk = new MkdSDK(); + setLoading(globalDispatch, true, state); + try { + const result = await sdk.request({ + endpoint: options?.endpoint, + method: options?.method, + body: options?.payload, + signal: options?.signal, + }); + + if (!result?.error) { + dataSuccess( + globalDispatch, + { message: result?.message, data: result?.data, error: false }, + state + ); + setLoading(globalDispatch, false, state); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "Success", + 4000, + "success" + ); + } + return { + ...result, + error: false, + data: result?.data || result?.model || result?.list, + message: result?.message, + }; + } else { + setLoading(globalDispatch, false, state); + if (options?.allowToast) { + showToast( + globalDispatch, + result?.message ?? "An Error Occurred", + 4000, + "error" + ); + } + return { + ...result, + error: true, + validation: result?.validation, + message: result?.message, + }; + } + } catch (error: unknown) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + setLoading(globalDispatch, false, state); + dataFailure(globalDispatch, { message, error: true }, state); + if (options?.allowToast) { + showToast(globalDispatch, message, 4000, "error"); + } + console.log("error?.response >>", err?.response); + tokenExpireError(authDispatch, message); + return { error: true, message }; + } +}; + +export function computeFilter( + field: string, + operator: string, + value: string | number +): string { + return `${field},${operator},${value}`; +} diff --git a/src/context/Global/GlobalConstants.ts b/src/context/Global/GlobalConstants.ts new file mode 100644 index 0000000..b7604fc --- /dev/null +++ b/src/context/Global/GlobalConstants.ts @@ -0,0 +1,56 @@ +export const REQUEST_LOADING = "REQUEST_LOADING"; +export const REQUEST_SUCCESS = "REQUEST_SUCCESS"; +export const REQUEST_FAILED = "REQUEST_FAILED"; +export const SET_GLOBAL_PROPERTY = "SET_GLOBAL_PROPERTY"; +export const ADD_BACKGROUND_PROCESS = "ADD_BACKGROUND_PROCESS"; +export const SET_BACKGROUND_PROCESSES = "SET_BACKGROUND_PROCESSES"; +export const REMOVE_BACKGROUND_PROCESS = "REMOVE_BACKGROUND_PROCESS"; + +interface RequestItemsType { + readonly viewModel: string; + readonly createModel: string; + readonly updateModel: string; + readonly listModel: string; + readonly deleteModel: string; + readonly customRequest: string; +} + +const RequestItems: RequestItemsType = { + viewModel: "viewModel", + createModel: "createModel", + updateModel: "updateModel", + listModel: "listModel", + deleteModel: "deleteModel", + customRequest: "customRequest", +} as const + +interface ViewsType { + readonly RouteList: string; + readonly BasicRouteEditor: string; + readonly AdvancedRouteEditor: string; +} + +const Views: ViewsType = { + RouteList: "routelist", + BasicRouteEditor: "basicrouteeditor", + AdvancedRouteEditor: "advancedrouteeditor", +} as const + +interface ViewsMapType { + readonly RouteList: string; + readonly RouteEditor: string; +} + +const ViewsMap: ViewsMapType = { + RouteList: "Route List", + RouteEditor: "Route Editor", +} as const + + +const BackgroundProcessStatus = { + PENDING: "PENDING", + REJECTED: "REJECTED", + FULFILLED: "FULFILLED", +} as const + +export { RequestItems, Views, ViewsMap,BackgroundProcessStatus }; diff --git a/src/context/Global/GlobalContext.tsx b/src/context/Global/GlobalContext.tsx new file mode 100644 index 0000000..f751b9a --- /dev/null +++ b/src/context/Global/GlobalContext.tsx @@ -0,0 +1,223 @@ +import React, { useReducer } from "react"; +import { + GlobalState, + GlobalAction, + GlobalContextType, + ToastStatus, +} from "./types"; +import { + REQUEST_FAILED, + REQUEST_LOADING, + REQUEST_SUCCESS, + SET_GLOBAL_PROPERTY, +} from "./GlobalConstants"; + +/** + * The Value of the Global State . + * @param {GlobalState} initialState + */ + +const initialState: GlobalState = { + globalMessage: "", + toastStatus: "success", + isOpen: true, + showBackButton: false, + path: "", + sessionExpired: false, + projectRow: null, + leftPanel: [], + middlePanel: [], + rightPanel: {}, + selectedComponent: 0, + rightComponentId: "", + selectedPageComponent: 0, + rooms: [], +}; + +export const GlobalContext = React.createContext({ + state: initialState, + dispatch: () => null, +}); + +const reducer = (state: GlobalState, action: GlobalAction): GlobalState => { + switch (action.type) { + case "SNACKBAR": + return { + ...state, + globalMessage: action.payload.message, + toastStatus: action.payload.toastStatus ?? state.toastStatus, + }; + case "SETPATH": + return { + ...state, + path: action.payload.path, + }; + case "OPEN_SIDEBAR": + return { + ...state, + isOpen: action.payload.isOpen, + }; + case "SHOW_BACKBUTTON": + return { + ...state, + showBackButton: action.payload.showBackButton, + }; + case "SET_PROJECT_ROW": + return { + ...state, + projectRow: action.payload, + }; + case "SET_LEFT_PANEL": + return { + ...state, + leftPanel: action.payload, + }; + case "SET_MIDDLE_PANEL": + return { + ...state, + middlePanel: action.payload, + }; + case "SET_RIGHT_PANEL": + return { + ...state, + rightPanel: action.payload, + rightComponentId: action.rightComponentId, + }; + case "SET_SELECTED_COMPONENT": + return { + ...state, + selectedComponent: action.payload, + }; + case "SET_SELECTED_PAGE_COMPONENT": + return { + ...state, + selectedPageComponent: action.payload, + }; + case "SETROOM": + const existingRoomIndex = state.rooms.findIndex( + (room) => room.position === action.payload.position + ); + if (existingRoomIndex !== -1) { + const updatedRooms = [...state.rooms]; + updatedRooms[existingRoomIndex] = action.payload; + return { + ...state, + rooms: updatedRooms, + }; + } else { + return { + ...state, + rooms: [...state.rooms, action.payload], + }; + } + case SET_GLOBAL_PROPERTY: + if (action.property.includes(".")) { + const [prop, field] = action.property.split("."); + const stateValue = state[prop as keyof GlobalState]; + return { + ...state, + [prop]: { + ...(typeof stateValue === 'object' && stateValue !== null ? stateValue : {}), + [field]: action.payload, + }, + }; + } + return { + ...state, + [action.property]: action.payload, + }; + case REQUEST_LOADING: + const loadingState = state[action.item as keyof GlobalState]; + return { + ...state, + [action.item]: { + ...(typeof loadingState === 'object' && loadingState !== null ? loadingState : {}), + loading: action.payload, + }, + }; + case REQUEST_SUCCESS: + const successState = state[action.item as keyof GlobalState]; + return { + ...state, + [action.item]: { + ...(typeof successState === 'object' && successState !== null ? successState : {}), + ...(action.payload as object), + error: false, + success: true, + loading: false, + }, + }; + case REQUEST_FAILED: + const failedState = state[action.item as keyof GlobalState]; + return { + ...state, + [action.item]: { + ...(typeof failedState === 'object' && failedState !== null ? failedState : {}), + ...(action.payload as object), + error: true, + success: false, + loading: false, + }, + }; + default: + return state; + } +}; + +/** + * @param {"success"| "error" | "warning"} toastStatus + * @param {any} dispatch + * @param {string} message + * @param {number} timeout + */ + +export const showToast = ( + dispatch: React.Dispatch, + message: string, + timeout: number = 3000, + toastStatus: ToastStatus = "success" +): void => { + dispatch({ + type: "SNACKBAR", + payload: { + message, + toastStatus, + }, + }); + + setTimeout(() => { + return dispatch({ + type: "SNACKBAR", + payload: { + message: "", + toastStatus: "success" + }, + }); + }, timeout); +}; + +export const setGlobalProjectRow = ( + dispatch: React.Dispatch, + data: any +): void => { + dispatch({ + type: "SET_PROJECT_ROW", + payload: data, + }); +}; + +interface GlobalProviderProps { + children: React.ReactNode; +} + +const GlobalProvider: React.FC = ({ children }) => { + const [state, dispatch] = useReducer(reducer, initialState); + + return ( + + {children} + + ); +}; + +export default GlobalProvider; diff --git a/src/context/Global/InitialGlobalStates.ts b/src/context/Global/InitialGlobalStates.ts new file mode 100644 index 0000000..8d1132f --- /dev/null +++ b/src/context/Global/InitialGlobalStates.ts @@ -0,0 +1,19 @@ +/** + * @property {boolean} loading + * @property {boolean} success + * @property {boolean} error + * @property {Array} data + * */ +export interface PropertyState { + loading: boolean; + success: boolean; + error: boolean; + data: any[]; +} + +export const PropertyInitialState: PropertyState = { + loading: false, + success: false, + error: false, + data: [], +}; diff --git a/src/context/Global/index.ts b/src/context/Global/index.ts new file mode 100644 index 0000000..d056f0f --- /dev/null +++ b/src/context/Global/index.ts @@ -0,0 +1,61 @@ +export { + default as GlobalProvider, + GlobalContext, + showToast, + setGlobalProjectRow, +} from "./GlobalContext"; +export { PropertyInitialState } from "./InitialGlobalStates"; + +export { + setGLobalProperty, + setLoading, + getSingleModel, + getManyByIds, + getMany, + createRequest, + updateRequest, + deleteRequest, + getList, + customRequest, + readImageUrl, + dataSuccess, + dataFailure, + type GetListOptions, + type GetManyOptions, + type GetSingleModelOptions, + type CreateRequestOptions, + type UpdateRequestOptions, + type DeleteRequestOptions, + type GetManyByIdsOptions, + type GetManyByIdsResult, + type GetListResult, + type CreateRequestResult, + type UpdateRequestResult, + type DeleteRequestResult, + type CustomRequestOptions, + type CustomRequestResult, + type ReadImageUrlResult, + type GetSingleModelResult, + type GetManyResult, +} from "./GlobalActions"; + +export { + RequestItems, + Views, + ViewsMap, + REQUEST_FAILED, + REQUEST_LOADING, + REQUEST_SUCCESS, + SET_GLOBAL_PROPERTY, +} from "./GlobalConstants"; + +export type { + GlobalState, + GlobalAction, + GlobalContextType, + ToastStatus, + Room, + RequestAction, + GlobalPropertyAction, + ApiError, +} from "./types"; diff --git a/src/context/Global/types.ts b/src/context/Global/types.ts new file mode 100644 index 0000000..fb13d34 --- /dev/null +++ b/src/context/Global/types.ts @@ -0,0 +1,85 @@ +export type ToastStatus = "success" | "error" | "warning" | 'info'; + +export interface Room { + position: number; + id: string; + name: string; + description?: string; + properties: Record; +} + +export interface PanelItem { + id: string; + type: string; + label: string; + properties: Record; +} + +export interface GlobalState extends Record { + globalMessage: string; + toastStatus: ToastStatus; + isOpen: boolean; + showBackButton: boolean; + path: string; + sessionExpired: boolean; + projectRow: Record | null; + leftPanel: PanelItem[]; + middlePanel: PanelItem[]; + rightPanel: Record; + selectedComponent: number; + rightComponentId: string; + selectedPageComponent: number; + openRouteChangeModal: boolean; + rooms: Room[]; +} + +export interface RequestAction { + item: string; + type: "REQUEST_LOADING" | "REQUEST_SUCCESS" | "REQUEST_FAILED"; + payload: unknown; +} + +export interface GlobalPropertyAction { + type: "SET_GLOBAL_PROPERTY"; + property: keyof GlobalState; + payload: unknown; +} + +export type GlobalAction = + | { type: "SNACKBAR"; payload: { message: string; toastStatus: ToastStatus } } + | { type: "SETPATH"; payload: { path: string } } + | { type: "OPEN_SIDEBAR"; payload: { isOpen: boolean } } + | { type: "SHOW_BACKBUTTON"; payload: { showBackButton: boolean } } + | { type: "SET_PROJECT_ROW"; payload: Record | null } + | { type: "SET_LEFT_PANEL"; payload: PanelItem[] } + | { type: "SET_MIDDLE_PANEL"; payload: PanelItem[] } + | { type: "SET_RIGHT_PANEL"; payload: Record; rightComponentId: string } + | { type: "SET_SELECTED_COMPONENT"; payload: number } + | { type: "SET_SELECTED_PAGE_COMPONENT"; payload: number } + | { type: "SETROOM"; payload: Room } + | { type: "UPDATEROOM"; payload: Room } + | { type: "DELETEROOM"; payload: { position: number } } + | RequestAction + | GlobalPropertyAction; + +export interface GlobalContextType { + state: GlobalState; + dispatch: React.Dispatch; +} + +export interface ApiErrorResponse { + message?: string; + data?: { + message?: string; + }; +} + +export class ApiError extends Error { + response?: ApiErrorResponse; + data?: ApiErrorResponse; + + constructor(message?: string) { + super(message); + this.name = 'ApiError'; + } +} \ No newline at end of file diff --git a/src/data/characters.ts b/src/data/characters.ts deleted file mode 100644 index 73ba4ae..0000000 --- a/src/data/characters.ts +++ /dev/null @@ -1,82 +0,0 @@ -export const characters = [ - { - id: '1', - name: 'Naruto Uzumaki (Baryon Mode)', - image: 'https://wallpapers.com/images/featured-full/naruto-baryon-mode-epz28fsvrytiv5le.jpg' - }, - { - id: '2', - name: 'Sasuke Uchiha (Rinnegan)', - image: 'https://static.wikia.nocookie.net/naruto/images/6/67/Sasuke_Rinnegan.png' - }, - { - id: '3', - name: 'Sakura Haruno (Byakugou Seal)', - image: 'https://preview.redd.it/any-figures-of-sakura-using-byakugou-seal-v0-yv8jueh9v7od1.jpeg?width=640&crop=smart&auto=webp&s=c8a0c85d9cce90b94e5e00651921450f7b0cb790' - }, - { - id: '4', - name: 'Kakashi Hatake (Dual Mangekyō Sharingan)', - image: 'https://static.wikia.nocookie.net/naruto/images/5/5f/Kakashi_Dual_Mangekyo_Sharingan.png' - }, - { - id: '5', - name: 'Madara Uchiha (Ten Tails Jinchūriki)', - image: 'https://static.wikia.nocookie.net/naruto/images/3/3d/Madara_Ten_Tails_Jinchuriki.png' - }, - { - id: '6', - name: 'Obito Uchiha (Ten Tails Jinchūriki)', - image: 'https://static.wikia.nocookie.net/naruto/images/1/1a/Obito_Ten_Tails_Jinchuriki.png' - }, - { - id: '7', - name: 'Itachi Uchiha (Edo Tensei)', - image: 'https://static.wikia.nocookie.net/naruto/images/9/95/Itachi_Edo_Tensei.png' - }, - { - id: '8', - name: 'Hashirama Senju (Sage Mode)', - image: 'https://static.wikia.nocookie.net/naruto/images/9/9b/Hashirama_Sage_Mode.png' - }, - { - id: '9', - name: 'Minato Namikaze (Six Paths Sage Mode)', - image: 'https://static.wikia.nocookie.net/naruto/images/3/3b/Minato_Six_Paths_Sage_Mode.png' - }, - { - id: '10', - name: 'Gaara (Shukaku Jinchūriki)', - image: 'https://static.wikia.nocookie.net/naruto/images/6/68/Gaara_Shukaku_Jinchuriki.png' - }, - { - id: '11', - name: 'Boruto Uzumaki (Kāma Seal)', - image: 'https://static.wikia.nocookie.net/naruto/images/6/6b/Boruto_Kama_Seal.png' - }, - { - id: '12', - name: 'Kawaki (Kāma Seal)', - image: 'https://static.wikia.nocookie.net/naruto/images/2/2a/Kawaki_Kama_Seal.png' - }, - { - id: '13', - name: 'Sarada Uchiha (Mangekyō Sharingan)', - image: 'https://static.wikia.nocookie.net/naruto/images/1/1e/Sarada_Mangekyo_Sharingan.png' - }, - { - id: '14', - name: 'Mitsuki (Sage Transformation)', - image: 'https://static.wikia.nocookie.net/naruto/images/4/4b/Mitsuki_Sage_Transformation.png' - }, - { - id: '15', - name: 'Momoshiki Ōtsutsuki (Fused Form)', - image: 'https://static.wikia.nocookie.net/naruto/images/4/4f/Momoshiki_Fused_Form.png' - }, - { - id: '16', - name: 'Isshiki Ōtsutsuki (Full Power Form)', - image: 'https://static.wikia.nocookie.net/naruto/images/c/cd/Isshiki_Full_Power_Form.png' - } -]; \ No newline at end of file diff --git a/src/depreacted_App.jsx b/src/depreacted_App.jsx new file mode 100644 index 0000000..5232c4e --- /dev/null +++ b/src/depreacted_App.jsx @@ -0,0 +1,49 @@ +import React from "react"; +import { AuthProvider } from "Context/Auth"; +import { GlobalProvider } from "Context/Global"; +import Main from "Routes/routes"; +import "@uppy/core/dist/style.css"; +import "@uppy/dashboard/dist/style.css"; +import { BrowserRouter as Router } from "react-router-dom"; +import "react-loading-skeleton/dist/skeleton.css"; +import { loadStripe } from "@stripe/stripe-js"; +import { Elements } from "@stripe/react-stripe-js"; + +import "@fontsource/inter"; // Defaults to weight 400 +import "@fontsource/roboto-mono"; // Defaults to weight 400 +import WireframeBuilderProvider from "Components/WireframeBuilder/reducers/WireframeBuilderContext"; +import { ErrorBoundary } from "Components/ErrorBoundary"; + +import Hotjar from "@hotjar/browser"; +import { LazyLoad } from "Components/LazyLoad"; + +const siteId = 5128711; +const hotjarVersion = 6; + +Hotjar.init(siteId, hotjarVersion); + +const stripePromise = loadStripe( + "pk_test_51Ll5ukBgOlWo0lDUrBhA2W7EX2MwUH9AR5Y3KQoujf7PTQagZAJylWP1UOFbtH4UwxoufZbInwehQppWAq53kmNC00UIKSmebO" +); + +function App() { + return ( + + + + + Error
    }> + + +
    + + + + + + + + ); +} + +export default App; diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/hooks/useContexts/index.ts b/src/hooks/useContexts/index.ts new file mode 100644 index 0000000..8ed88b3 --- /dev/null +++ b/src/hooks/useContexts/index.ts @@ -0,0 +1 @@ +export {default as useContexts} from "./useContexts" \ No newline at end of file diff --git a/src/hooks/useContexts/useContexts.tsx b/src/hooks/useContexts/useContexts.tsx new file mode 100644 index 0000000..512ce38 --- /dev/null +++ b/src/hooks/useContexts/useContexts.tsx @@ -0,0 +1,233 @@ +import { useCallback, useContext } from "react"; +import { + AuthContext, + tokenExpireError as tokenExpiredError, + AuthState, + AuthContextType, + AuthAction, +} from "@/context/Auth"; + +import { + GlobalContext, + showToast as toast, + getSingleModel, + getList, + getManyByIds, + updateRequest, + createRequest, + deleteRequest, + customRequest, + setGLobalProperty, + GlobalState, + GlobalContextType, + GlobalAction, + GetListOptions, + GetSingleModelOptions, + GetManyByIdsOptions, + UpdateRequestOptions, + CreateRequestOptions, + DeleteRequestOptions, + CustomRequestOptions, +} from "@/context/Global"; +import { ToastStatusEnum } from "@/utils/Enums"; + +interface ApiResponse { + error: boolean; + data?: T; + message?: string; +} + +interface UseContextsResult { + globalState: GlobalState; + authState: AuthState; + authDispatch: React.Dispatch; + globalDispatch: React.Dispatch; + showToast: ( + message: string, + duration?: number, + status?: ToastStatusEnum + ) => void; + setGlobalState: (state: string, value: any) => void; + tokenExpireError: (message: string) => void; + getMany: (table: string, options: GetListOptions) => Promise; + getManyByIds: ( + table: string, + ids: (string | number)[], + options: GetManyByIdsOptions + ) => Promise; + getSingle: ( + table: string, + id: string | number, + options: GetSingleModelOptions + ) => Promise; + update: ( + table: string, + id: string | number, + data: Record, + options: UpdateRequestOptions + ) => Promise; + create: ( + table: string, + data: Record, + options: CreateRequestOptions + ) => Promise; + remove: ( + table: string, + id: string | number, + options: DeleteRequestOptions + ) => Promise; + custom: (options: CustomRequestOptions) => Promise; +} + +const useContexts = (): UseContextsResult => { + const { state: globalState, dispatch: globalDispatch } = + useContext(GlobalContext); + const { state: authState, dispatch: authDispatch } = + useContext(AuthContext); + + const showToast = useCallback( + ( + message: string, + duration = 5000, + status: ToastStatusEnum = ToastStatusEnum.SUCCESS + ) => { + toast(globalDispatch, message, duration, status); + }, + [globalDispatch] + ); + + const setGlobalState = useCallback( + (state: string, value: any) => { + setGLobalProperty(globalDispatch, value, state); + }, + [globalDispatch] + ); + + const tokenExpireError = useCallback( + (message: string) => { + tokenExpiredError(authDispatch, message); + }, + [authDispatch] + ); + + const getMany = useCallback( + async (table: string, options: GetListOptions): Promise => { + return await getList(globalDispatch, authDispatch, table, options); + }, + [globalDispatch, authDispatch] + ); + + const getManyById = useCallback( + async ( + table: string, + ids: Array, + options: GetManyByIdsOptions + ): Promise => { + return await getManyByIds( + globalDispatch, + authDispatch, + table, + ids, + options + ); + }, + [globalDispatch, authDispatch] + ); + + const getSingle = useCallback( + async ( + table: string, + id: string | number, + options: GetSingleModelOptions + ): Promise => { + return await getSingleModel( + globalDispatch, + authDispatch, + table, + id, + options + ); + }, + [globalDispatch, authDispatch] + ); + + const update = useCallback( + async ( + table: string, + id: string | number, + data: Record, + options: UpdateRequestOptions + ): Promise => { + return await updateRequest( + globalDispatch, + authDispatch, + table, + id, + data, + options + ); + }, + [globalDispatch, authDispatch] + ); + + const create = useCallback( + async ( + table: string, + data: Record, + options: CreateRequestOptions + ): Promise => { + return await createRequest( + globalDispatch, + authDispatch, + table, + data, + options + ); + }, + [globalDispatch, authDispatch] + ); + + const remove = useCallback( + async ( + table: string, + id: string | number, + options: DeleteRequestOptions + ): Promise => { + return await deleteRequest( + globalDispatch, + authDispatch, + table, + id, + {}, + options + ); + }, + [globalDispatch, authDispatch] + ); + + const custom = useCallback( + async (options: CustomRequestOptions): Promise => { + return await customRequest(globalDispatch, authDispatch, options); + }, + [globalDispatch, authDispatch] + ); + + return { + globalState, + authState, + globalDispatch, + authDispatch, + showToast, + setGlobalState, + tokenExpireError, + getMany, + getManyByIds: getManyById, + getSingle, + update, + create, + remove, + custom, + }; +}; + +export default useContexts; diff --git a/src/hooks/useDate/index.ts b/src/hooks/useDate/index.ts new file mode 100644 index 0000000..a229f4c --- /dev/null +++ b/src/hooks/useDate/index.ts @@ -0,0 +1 @@ +export { default as useDate } from "./useDate"; diff --git a/src/hooks/useDate/useDate.tsx b/src/hooks/useDate/useDate.tsx new file mode 100644 index 0000000..aa250b3 --- /dev/null +++ b/src/hooks/useDate/useDate.tsx @@ -0,0 +1,31 @@ +const useDate = (): { + convertDate: ( + date: string | number | Date, + opts?: Intl.DateTimeFormatOptions + ) => string; +} => { + + const convertDate = ( + date: string | number | Date, + opts?: Intl.DateTimeFormatOptions + ): string => { + const newDate = new Date(date); + + const options: Intl.DateTimeFormatOptions = { + year: "2-digit", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + ...opts + } + + return newDate.toLocaleDateString(undefined, options); + }; + + return { + convertDate, + }; +}; + +export default useDate; diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/hooks/useProfile/index.ts b/src/hooks/useProfile/index.ts new file mode 100644 index 0000000..9a42564 --- /dev/null +++ b/src/hooks/useProfile/index.ts @@ -0,0 +1 @@ +export { default as useProfile } from "./useProfile"; diff --git a/src/hooks/useProfile/useProfile.tsx b/src/hooks/useProfile/useProfile.tsx new file mode 100644 index 0000000..2894390 --- /dev/null +++ b/src/hooks/useProfile/useProfile.tsx @@ -0,0 +1,65 @@ +import React, { useEffect, useState } from "react"; +import { useSDK } from "../useSDK"; +import { useContexts } from "../useContexts"; +import { ApiError } from "@/context/Global"; + +const useProfile = () => { + const { sdk } = useSDK(); + + const { + authState: { profile: AuthProfile }, + authDispatch: dispatch, + tokenExpireError, + } = useContexts(); + + const [profile, setProfile] = useState | null>(null); + const [refresh, setRefresh] = useState(false); + + const getProfile = React.useCallback(() => { + (async () => { + try { + const role = localStorage.getItem("role"); + if (!role) { + return; + } + const result = await sdk.getProfile(role); + console.log(result); + if (!result?.error) { + setProfile(() => ({ + ...result?.model, + role: result?.model?.role ?? result?.model?.role_id, + })); + dispatch({ + type: "UPDATE_PROFILE", + payload: { + ...result?.model, + role: result?.model?.role ?? result?.model?.role_id, + }, + }); + } + } catch (error) { + const err = error as ApiError; + const message = + err?.response?.data?.message ?? err?.message ?? "An error occurred"; + tokenExpireError(message); + } + })(); + }, [profile]); + + useEffect(() => { + if (!AuthProfile || refresh) { + getProfile(); + } else { + setProfile(() => AuthProfile); + } + }, [AuthProfile, refresh]); + + return { + profile, + getProfile, + refresh, + setRefresh, + }; +}; + +export default useProfile; diff --git a/src/hooks/useSDK/index.ts b/src/hooks/useSDK/index.ts new file mode 100644 index 0000000..46a3710 --- /dev/null +++ b/src/hooks/useSDK/index.ts @@ -0,0 +1 @@ +export { default as useSDK } from "./useSDK"; diff --git a/src/hooks/useSDK/useSDK.tsx b/src/hooks/useSDK/useSDK.tsx new file mode 100644 index 0000000..b2340da --- /dev/null +++ b/src/hooks/useSDK/useSDK.tsx @@ -0,0 +1,27 @@ +import { useMemo } from "react"; +import { operations } from "@/utils"; +import MkdSDK from "@/utils/MkdSDK"; +import TreeSDK from "@/utils/TreeSDK"; + +interface UseSDKReturnType { + sdk: MkdSDK; + tdk: TreeSDK; + projectId: string, + operations: typeof operations; +} + +const useSDK = (): UseSDKReturnType => { + const sdk = useMemo(() => { + return new MkdSDK(); + }, [MkdSDK]); + + const tdk = useMemo(() => { + return new TreeSDK(); + }, [TreeSDK]); + + const projectId = sdk.getProjectId() + + return { sdk, tdk, projectId, operations }; +}; + +export default useSDK; diff --git a/src/index.css b/src/index.css index b5c61c9..6e84bab 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,271 @@ @tailwind base; @tailwind components; @tailwind utilities; +* { + margin: 0; + padding: 0; + box-sizing: border-box; + transition: all 0.5s ease-in-out; +} +html { + font-size: 0.875rem; +} +::-webkit-scrollbar { + width: 0.625rem; + border-radius: 0.75rem; +} + +::-webkit-scrollbar-thumb { + background-color: #a8a8a8; + border-radius: 0.75rem; +} +body { + position: relative; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} +.react-toggle { + touch-action: pan-x; + + display: inline-block; + position: relative; + cursor: pointer; + background-color: transparent; + border: 0; + padding: 0; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; +} + +.react-toggle-screenreader-only { + border: 0; + clip: rect(0 0 0 0); + height: 0.0625rem; + margin: -0.0625rem; + overflow: hidden; + padding: 0; + position: absolute; + width: 0.0625rem; +} + +.react-toggle--disabled { + cursor: not-allowed; + opacity: 0.5; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; +} + +.react-toggle-track { + width: 3.125rem; + height: 1.5rem; + padding: 0; + border-radius: 1.875rem; + background-color: #e4f1f7; + -webkit-transition: all 0.2s ease; + -moz-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #eeeeee; +} + +.react-toggle--checked .react-toggle-track, +.react-toggle--checked .react-toggle-track:hover { + background-color: #4f46e5; +} + +.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #4f46e5; +} + +.react-toggle-track-check { + position: absolute; + width: 0.875rem; + height: 0.625rem; + top: 0rem; + bottom: 0rem; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + left: 0.5rem; + opacity: 0; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-check { + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle-track-x { + position: absolute; + width: 0.625rem; + height: 0.625rem; + top: 0rem; + bottom: 0rem; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + right: 0.625rem; + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-x { + opacity: 0; +} + +.react-toggle-thumb { + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; + position: absolute; + top: 0.0625rem; + left: 0.0625rem; + width: 1.375rem; + height: 1.375rem; + border: 0.0625rem solid #fafafa; + border-radius: 50%; + background-color: #fafafa; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + -webkit-transition: all 0.25s ease; + -moz-transition: all 0.25s ease; + transition: all 0.25s ease; +} + +.react-toggle--checked .react-toggle-thumb { + left: 1.6875rem; + border-color: #4f46e5; +} + +.react-toggle--focus .react-toggle-thumb { + -webkit-box-shadow: 0rem 0rem 0.1875rem 0.125rem #4f46e5; + -moz-box-shadow: 0rem 0rem 0.1875rem 0.125rem #4f46e5; + box-shadow: 0rem 0rem 0.125rem 0.1875rem #4f46e5; +} + +.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb { + -webkit-box-shadow: 0rem 0rem 0.3125rem 0.3125rem #4f46e5; + -moz-box-shadow: 0rem 0rem 0.3125rem 0.3125rem #4f46e5; + box-shadow: 0rem 0rem 0.3125rem 0.3125rem #4f46e5; +} +.scrollbar-hide::-webkit-scrollbar { + display: none; +} +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} +.custom-tooltip { + max-width: 200px; /* Set a fixed width */ + white-space: pre-wrap; /* Allow text to wrap to the next line */ + word-wrap: break-word; /* Break long words */ +} +.sidebar-holder { + width: 100%; + min-width: 15rem; + max-width: 15rem; + position: relative; + background: #151515; + color: #fff; + z-index: 2; + /* transition: all 0.3s; */ + min-height: 100vh; + overflow: hidden; + transition: 0.2s; +} +.open-nav { + min-width: 0rem !important; + max-width: 0rem !important; + width: 0 !important; + transition: 0.2s; + opacity: 0; +} + +.sidebar-list ul li a { + padding: 0.625rem; + display: block; + width: 100%; + font-size: 0.875rem; + font-weight: 600; + transition: 0.2s ease-in; + text-transform: capitalize; +} + +.sidebar-list .active-nav { + padding: 0.75rem; + color: #262626; + border-radius: 0.375rem; + background: #f4f4f4; +} + +.sidebar-list .active-nav:hover { + background: #f4f4f4; +} + +.sidebar-list ul li a:hover { + color: #262626; +} + +.page-header { + width: 100%; + padding: 1.25rem; + background: white; +} +.page-header span { + cursor: pointer; + display: block; + width: fit-content; + font-size: 1.25rem; +} + +.center-svg { + aspect-ratio: 1/1; + align-items: center; + justify-content: center; + line-height: 1.2em !important; +} + +.uppy-Dashboard-inner { + width: 100% !important; +} + +@media screen and (max-width: 47.9375rem) { + .sidebar-holder { + width: 100%; + min-width: 12.5rem; + max-width: 12.5rem; + position: fixed; + top: 0; + left: 0; + } + .page-header span { + margin-left: auto; + } +} diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..0f4e1a1 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import "./output.css"; +// import "./App.css"; +import "slick-carousel/slick/slick.css"; +import "slick-carousel/slick/slick-theme.css"; +import App from "./App"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { fas } from "@fortawesome/free-solid-svg-icons"; +import { far } from "@fortawesome/free-regular-svg-icons"; +import { fab } from "@fortawesome/free-brands-svg-icons"; + +library.add(fas, far, fab); + +const root = ReactDOM.createRoot(document.getElementById("root")); + +root.render( + // + + // +); diff --git a/src/logo.svg b/src/logo.svg new file mode 100644 index 0000000..2b2e4e5 --- /dev/null +++ b/src/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx deleted file mode 100644 index ea9e363..0000000 --- a/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; -import App from './App.tsx'; -import './index.css'; - -createRoot(document.getElementById('root')!).render( - - - -); diff --git a/src/output.css b/src/output.css new file mode 100644 index 0000000..7c37269 --- /dev/null +++ b/src/output.css @@ -0,0 +1,263 @@ +/* @tailwind base; +@tailwind components; +@tailwind utilities; */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + transition: all 0.5s ease-in-out; +} + +html { + font-size: 0.875rem; +} + +::-webkit-scrollbar { + width: 0.625rem; + border-radius: 0.75rem; +} + +::-webkit-scrollbar-thumb { + background-color: #a8a8a8; + border-radius: 0.75rem; +} + +body { + position: relative; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} + +.react-toggle { + touch-action: pan-x; + display: inline-block; + position: relative; + cursor: pointer; + background-color: transparent; + border: 0; + padding: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; +} + +.react-toggle-screenreader-only { + border: 0; + clip: rect(0 0 0 0); + height: 0.0625rem; + margin: -0.0625rem; + overflow: hidden; + padding: 0; + position: absolute; + width: 0.0625rem; +} + +.react-toggle--disabled { + cursor: not-allowed; + opacity: 0.5; + transition: opacity 0.25s; +} + +.react-toggle-track { + width: 3.125rem; + height: 1.5rem; + padding: 0; + border-radius: 1.875rem; + background-color: #e4f1f7; + transition: all 0.2s ease; +} + +.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #eeeeee; +} + +.react-toggle--checked .react-toggle-track, +.react-toggle--checked .react-toggle-track:hover { + background-color: #4f46e5; +} + +.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #4f46e5; +} + +.react-toggle-track-check { + position: absolute; + width: 0.875rem; + height: 0.625rem; + top: 0rem; + bottom: 0rem; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + left: 0.5rem; + opacity: 0; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-check { + opacity: 1; + transition: opacity 0.25s ease; +} + +.react-toggle-track-x { + position: absolute; + width: 0.625rem; + height: 0.625rem; + top: 0rem; + bottom: 0rem; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + right: 0.625rem; + opacity: 1; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-x { + opacity: 0; +} + +.react-toggle-thumb { + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; + position: absolute; + top: 0.0625rem; + left: 0.0625rem; + width: 1.375rem; + height: 1.375rem; + border: 0.0625rem solid #fafafa; + border-radius: 50%; + background-color: #fafafa; + box-sizing: border-box; + transition: all 0.25s ease; +} + +.react-toggle--checked .react-toggle-thumb { + left: 1.6875rem; + border-color: #4f46e5; +} + +.react-toggle--focus .react-toggle-thumb { + box-shadow: 0rem 0rem 0.125rem 0.1875rem #4f46e5; +} + +.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb { + box-shadow: 0rem 0rem 0.3125rem 0.3125rem #4f46e5; +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.custom-tooltip { + max-width: 200px; + /* Set a fixed width */ + white-space: pre-wrap; + /* Allow text to wrap to the next line */ + word-wrap: break-word; + /* Break long words */ +} + +.sidebar-holder { + width: 100%; + min-width: 15rem; + max-width: 15rem; + position: relative; + background: #151515; + color: #fff; + z-index: 2; + /* transition: all 0.3s; */ + min-height: 100vh; + overflow: hidden; + transition: 0.2s; +} + +.open-nav { + min-width: 0rem !important; + max-width: 0rem !important; + width: 0 !important; + transition: 0.2s; + opacity: 0; +} + +.sidebar-list ul li a { + padding: 0.625rem; + display: block; + width: 100%; + font-size: 0.875rem; + font-weight: 600; + transition: 0.2s ease-in; + text-transform: capitalize; +} + +.sidebar-list .active-nav { + padding: 0.75rem; + color: #262626; + border-radius: 0.375rem; + background: #f4f4f4; +} + +.sidebar-list .active-nav:hover { + background: #f4f4f4; +} + +.sidebar-list ul li a:hover { + color: #262626; +} + +.page-header { + width: 100%; + padding: 1.25rem; + background: white; +} + +.page-header span { + cursor: pointer; + display: block; + width: -moz-fit-content; + width: fit-content; + font-size: 1.25rem; +} + +.center-svg { + aspect-ratio: 1/1; + align-items: center; + justify-content: center; + line-height: 1.2em !important; +} + +.uppy-Dashboard-inner { + width: 100% !important; +} + +@media screen and (max-width: 47.9375rem) { + .sidebar-holder { + width: 100%; + min-width: 12.5rem; + max-width: 12.5rem; + position: fixed; + top: 0; + left: 0; + } + + .page-header span { + margin-left: auto; + } +} diff --git a/src/pages/404/NotFoundPage.tsx b/src/pages/404/NotFoundPage.tsx new file mode 100644 index 0000000..9d3fbfb --- /dev/null +++ b/src/pages/404/NotFoundPage.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import { Loader } from "@/components/Loader"; + +const NotFoundPage = () => { + const [loading, setLoading] = React.useState(true); + + React.useEffect(() => { + setTimeout(() => { + setLoading(false); + }, 4000); + }, []); + + return ( + <> + {loading ? ( + + ) : ( +
    + Not Found +
    + )} + + ); +}; + +export default NotFoundPage; diff --git a/src/pages/404/index.ts b/src/pages/404/index.ts new file mode 100644 index 0000000..7c6fc6a --- /dev/null +++ b/src/pages/404/index.ts @@ -0,0 +1,2 @@ +import { lazy } from "react"; +export const NotFoundPage = lazy(() => import("./NotFoundPage")); diff --git a/src/pages/Admin/Add/AddAdminAndroidPage.tsx b/src/pages/Admin/Add/AddAdminAndroidPage.tsx new file mode 100644 index 0000000..7d6b732 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminAndroidPage.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { GlobalContext } from "@/context/Global"; +import LeftPanel from "@/components/MobileUiBuilder/AndroidUI/LeftPanel"; +import MiddlePanel from "@/components/MobileUiBuilder/AndroidUI/MiddlePanel"; +import RightPanel from "@/components/MobileUiBuilder/AndroidUI/RightPanel"; + +const AddAdminAndroidPage = () => { + const { state, dispatch: globalDispatch } = React.useContext(GlobalContext); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "email", + }, + }); + }, []); + + return ( +
    +
    +

    Android

    +
    +
    + + + +
    +
    + ); +}; + +export default AddAdminAndroidPage; diff --git a/src/pages/Admin/Add/AddAdminProjectTablePage.tsx b/src/pages/Admin/Add/AddAdminProjectTablePage.tsx new file mode 100644 index 0000000..96fe9c6 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminProjectTablePage.tsx @@ -0,0 +1,384 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import "react-quill/dist/quill.snow.css"; + +const AddProjectPage = ({ setSidebar }) => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + name: yup.string(), + slug: yup.string(), + secret: yup.string(), + api_domain: yup.string(), + api_domain_id: yup.string(), + frontend_domain: yup.string(), + frontend_domain_id: yup.string(), + wireframe_id: yup.string(), + api_deploy_status: yup.string(), + frontend_deploy_status: yup.string(), + configuration: yup.string(), + validations: yup.string(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [isUpdating, setIsUpdating] = React.useState(false); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + setIsUpdating(true); + try { + sdk.setTable("project"); + + const result = await sdk.callRestAPI( + { + name: _data.name, + slug: _data.slug, + secret: _data.secret, + api_domain: _data.api_domain, + api_domain_id: _data.api_domain_id, + frontend_domain: _data.frontend_domain, + frontend_domain_id: _data.frontend_domain_id, + wireframe_id: _data.wireframe_id, + api_deploy_status: _data.api_deploy_status, + frontend_deploy_status: _data.frontend_deploy_status, + configuration: _data.configuration, + validations: _data.validations, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/project"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + setIsUpdating(false); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "project", + }, + }); + }, []); + + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Add Project +
    +
    + + +
    +
    +
    +
    + + +

    {errors.name?.message}

    +
    + +
    + + +

    {errors.slug?.message}

    +
    + +
    + + +

    + {errors.secret?.message} +

    +
    + +
    + + +

    + {errors.api_domain?.message} +

    +
    + +
    + + +

    + {errors.api_domain_id?.message} +

    +
    + +
    + + +

    + {errors.frontend_domain?.message} +

    +
    + +
    + + +

    + {errors.frontend_domain_id?.message} +

    +
    + +
    + + +

    + {errors.wireframe_id?.message} +

    +
    + +
    + + +

    + {errors.api_deploy_status?.message} +

    +
    + +
    + + +

    + {errors.frontend_deploy_status?.message} +

    +
    + +
    + + +

    + {errors.configuration?.message} +

    +
    + +
    + + +

    + {errors.validations?.message} +

    +
    +
    +
    + ); +}; + +export default AddProjectPage; diff --git a/src/pages/Admin/Add/AddAdminSettingTablePage.tsx b/src/pages/Admin/Add/AddAdminSettingTablePage.tsx new file mode 100644 index 0000000..6e837e6 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminSettingTablePage.tsx @@ -0,0 +1,149 @@ + +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import 'react-quill/dist/quill.snow.css'; + +const AddSettingPage = ({ setSidebar }) => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + + setting_key: yup.string(), + setting_value: yup.string(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [isUpdating, setIsUpdating] = React.useState(false); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + setIsUpdating(true); + try { + + + sdk.setTable("setting"); + + const result = await sdk.callRestAPI( + { + + setting_key: _data.setting_key, + setting_value: _data.setting_value, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/setting"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("setting_key", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + }; + setIsUpdating(false); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "setting", + }, + }); + }, []); + + return ( +
    +
    +
    + setSidebar(false)} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"> + + + Add Setting +
    +
    + + +
    +
    +
    +
    + + +

    + {errors.setting_key?.message} +

    +
    + + +
    + + +

    + {errors.setting_value?.message} +

    +
    +
    +
    + ); +}; + +export default AddSettingPage; + + diff --git a/src/pages/Admin/Add/AddAdminSowTablePage.tsx b/src/pages/Admin/Add/AddAdminSowTablePage.tsx new file mode 100644 index 0000000..f1bf204 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminSowTablePage.tsx @@ -0,0 +1,207 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; +import "react-quill/dist/quill.snow.css"; + +const AddSowPage = ({ + setSidebar, + onSowCreated, + action = "navigate", + wireframe, +}) => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + name: yup.string(), + transcripts: yup.string(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const [isUpdating, setIsUpdating] = React.useState(false); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + fileName: target.files[0].name, + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (_data) => { + let sdk = new MkdSDK(); + setIsUpdating(true); + try { + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + _data[item] = uploadResult.url; + } + + sdk.setTable("sow"); + const result = await sdk.callRestAPI( + { + name: _data.name, + pdf_file: _data.pdf_file, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + switch (action) { + case "navigate": + return navigate("/admin/requirements"); + case "close": + if (onSowCreated) { + onSowCreated(result?.data); + } + break; + } + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + setIsUpdating(false); + }; + + React.useEffect(() => { + setValue("name", wireframe?.name); + }, []); + + // React.useEffect(() => { + // globalDispatch({ + // type: "SETPATH", + // payload: { + // path: action === "navigate" ? "sow" : "wireframe", + // }, + // }); + // }, []); + + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Add SOW +
    +
    + + +
    +
    +
    +
    + + +

    {errors.name?.message}

    +
    + +
    +
    + +
    +

    + {fileObj.pdf_file + ? fileObj.pdf_file.fileName + : "Select a PDF Requirement"} +

    +
    +
    +
    + ); +}; + +export default AddSowPage; diff --git a/src/pages/Admin/Add/AddAdminUserPage.tsx b/src/pages/Admin/Add/AddAdminUserPage.tsx new file mode 100644 index 0000000..234c1a0 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminUserPage.tsx @@ -0,0 +1,183 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext, showToast } from "@/context/Global"; +import { tokenExpireError } from "@/context/Auth"; + +const AddAdminUserPage = ({ setSidebar }) => { + const schema = yup + .object({ + email: yup.string().email().required(), + password: yup.string().required(), + role: yup.string(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [isUpdating, setIsUpdating] = React.useState(false); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const selectRole = [ + { name: "role", value: "admin" }, + { name: "role", value: "employee" }, + ]; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + setIsUpdating(true); + try { + const result = await sdk.register(data.email, data.password, data.role); + if (!result.error) { + showToast(dispatch, "Added"); + navigate("/admin/users"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setError("email", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + setIsUpdating(false); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "users", + }, + }); + }, []); + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Add User +
    +
    + + +
    +
    +
    +
    + + +

    {errors.email?.message}

    +
    +
    + + +
    +
    + + +

    + {errors.password?.message} +

    +
    +
    +
    + ); +}; + +export default AddAdminUserPage; diff --git a/src/pages/Admin/Add/AddAdminUserTablePage.tsx b/src/pages/Admin/Add/AddAdminUserTablePage.tsx new file mode 100644 index 0000000..62b30cd --- /dev/null +++ b/src/pages/Admin/Add/AddAdminUserTablePage.tsx @@ -0,0 +1,257 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext, showToast } from "@/context/Global"; +import { tokenExpireError } from "@/context/Auth"; + +const AddAdminUserPage = () => { + const schema = yup + .object({ + first_name: yup.string().required(), + last_name: yup.string().required(), + email: yup.string().email().required(), + password: yup.string().required(), + role: yup.string(), + }) + .required(); + const [userRole, setUserRole] = React.useState("admin"); + const { dispatch } = React.useContext(GlobalContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const selectRole = [ + { name: "role", value: "admin" }, + { name: "role", value: "staff" }, + { name: "role", value: "company" }, + ]; + + /** + * + * + * Use /user/put to update user remaining info after registration success + * use /profile/put to update profile info + */ + const onSubmit = async (data) => { + const first_name = data.first_name; + const last_name = data.last_name; + let sdk = new MkdSDK(); + + try { + if (userRole === "staff") { + if (data.company_id) { + const result = await sdk.callRawAPI( + `/v2/api/lambda/company/${data.company_id}/user-add`, + { + email: data.email, + password: data.password, + role: userRole, + first_name, + last_name, + verify: 1, + }, + "POST" + ); + + if (!result.error) { + showToast(dispatch, "Added"); + navigate("/admin/user"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } else { + showToast(globalDispatch, "company id needed"); + } + } else { + const result = await sdk.createUser( + data.email, + data.password, + userRole, + first_name, + last_name + ); + + if (!result.error) { + showToast(dispatch, "Added"); + navigate("/admin/user"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } + } catch (error) { + setError("email", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "users", + }, + }); + }, []); + + return ( +
    +

    Add User

    +
    +
    + + +

    + {errors.first_name?.message} +

    +
    +
    + + +

    + {errors.last_name?.message} +

    +
    +
    + + +

    {errors.email?.message}

    +
    +
    + + +
    + {userRole === "staff" && ( +
    + + +

    + {errors.company_id?.message} +

    +
    + )} + +
    + + +

    + {errors.password?.message} +

    +
    + +
    +
    + ); +}; + +export default AddAdminUserPage; diff --git a/src/pages/Admin/Add/AddAdminWireframeTablePage.tsx b/src/pages/Admin/Add/AddAdminWireframeTablePage.tsx new file mode 100644 index 0000000..b5986f5 --- /dev/null +++ b/src/pages/Admin/Add/AddAdminWireframeTablePage.tsx @@ -0,0 +1,162 @@ +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { useNavigate } from "react-router-dom"; +import { useContexts } from "@/hooks/useContexts"; +import { useSDK } from "@/hooks/useSDK"; +import { MkdInput } from "@/components/MkdInput"; +import { LazyLoad } from "@/components/LazyLoad"; +import { MkdButton } from "@/components/MkdButton"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { useProfile } from "@/hooks/useProfile"; +import { ToastStatusEnum } from "@/utils/Enums"; +import { useEffect, useState } from "react"; +import { MKD_DOMAIN } from "@/utils"; +interface AddWireframePageProps { + onClose: () => void; + onSuccess: (e?: any) => void; +} + +const AddWireframePage = ({ onClose, onSuccess }: AddWireframePageProps) => { + const { sdk } = useSDK(); + + const { showToast, tokenExpireError, create } = useContexts(); + + const { profile } = useProfile(); + const [loading, setLoading] = useState(false); + + const navigate = useNavigate(); + + const schema = yup + .object({ + name: yup + .string() + .matches(/^[a-zA-Z0-9 ]*$/, "Only strings and numbers are allowed") + .required("name is required"), + hostname: yup.string().required("hostname is required"), + slug: yup.string().required("slug is required"), + }) + .required(); + + const { + register, + handleSubmit, + setError, + setValue, + watch, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const { slug } = watch(); + + const onSubmit = async (_data: yup.InferType) => { + try { + setLoading(true); + const payload = { + name: _data.name, + slug: _data.slug, + hostname: _data.hostname, + }; + + const result = await create("project", payload, { + role: profile?.role, + allowToast: true, + }); + + if (result?.error) { + throw new Error(result?.message); + } + + if (onSuccess) { + onSuccess(); + } + } catch (error: any) { + setError("slug", { + type: "manual", + message: error.message, + }); + showToast(error.message, 4000, ToastStatusEnum.ERROR); + tokenExpireError(error.message); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + const hostname = `${slug ? slug : ""}.${MKD_DOMAIN}`; + setValue("hostname", hostname); + }, [slug]); + + return ( +
    +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + +
    + + + Cancel + + + + + Submit + + +
    +
    +
    + ); +}; + +export default AddWireframePage; diff --git a/src/pages/Admin/Auth/AdminForgotPage.tsx b/src/pages/Admin/Auth/AdminForgotPage.tsx new file mode 100644 index 0000000..d2fe8b4 --- /dev/null +++ b/src/pages/Admin/Auth/AdminForgotPage.tsx @@ -0,0 +1,121 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { Link } from "react-router-dom"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { GlobalContext, showToast } from "@/context/Global"; +import { tokenExpireError } from "@/context/Auth"; + +const AdminForgotPage = () => { + const [submitLoading, setSubmitLoading] = useState(false); + + const schema = yup + .object({ + email: yup.string().email().required(), + }) + .required(); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const { dispatch } = React.useContext(GlobalContext); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + try { + setSubmitLoading(true); + const result = await sdk.forgot(data.email); + + if (!result.error) { + showToast(dispatch, "Reset Code Sent"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + setSubmitLoading(false); + } catch (error) { + setSubmitLoading(false); + setError("email", { + type: "manual", + message: error.response.data.message + ? error.response.data.message + : error.message, + }); + tokenExpireError( + dispatch, + error.response.data.message + ? error.response.data.message + : error.message + ); + } + }; + + return ( + <> +
    +
    +
    + + +

    + {errors && errors.email?.message} +

    +
    + +
    + + Forgot Password + + + Login? + +
    +
    +

    + © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

    +
    + + ); +}; + +export default AdminForgotPage; diff --git a/src/pages/Admin/Auth/AdminLoginPage.tsx b/src/pages/Admin/Auth/AdminLoginPage.tsx new file mode 100644 index 0000000..1f89eca --- /dev/null +++ b/src/pages/Admin/Auth/AdminLoginPage.tsx @@ -0,0 +1,217 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { Link, useLocation } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { LoginBgNew } from "@/assets/images"; +import { useContexts } from "@/hooks/useContexts"; + +let sdk = new MkdSDK(); + +const AdminLoginPage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + password: yup.string().required(), + }) + .required(); + + const { authDispatch: dispatch, showToast, } = useContexts(); + + const [submitLoading, setSubmitLoading] = useState(false); + const [showPassword, setShowPassword] = useState(false); + const location = useLocation(); + + const searchParams = new URLSearchParams(location.search); + const redirect_uri = searchParams.get("redirect_uri"); + + const navigate = useNavigate(); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + try { + setSubmitLoading(true); + const result = await sdk.login(data.email, data.password, "super_admin"); + console.log('result', result) + if (!result.error) { + dispatch({ + type: "LOGIN", + payload: result as any, + }); + showToast("Succesfully Logged In", 4000, "success"); + navigate(redirect_uri ?? "/admin/build"); + } else { + setSubmitLoading(false); + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setSubmitLoading(false); + showToast( + error?.response?.data?.message + ? error?.response?.data?.message + : error?.message, + 4000, + "error" + ); + setError("email", { + type: "manual", + message: error?.response?.data?.message + ? error?.response?.data?.message + : error?.message, + }); + } + }; + + return ( +
    +
    +
    + + + + +
    + Welcome Back +
    +
    + Don’t have account? {" "} + + Sign up here + +
    + +
    +
    + + +

    +
    +
    + +
    +
    + +
    + setShowPassword(!showPassword)} + > + {showPassword ? ( + + + + ) : ( + + + + + )} + +
    +

    + {/* {errors?.password?.message} */} +

    +
    +
    +
    + +
    + + Forgot password + +
    + + Sign in + +
    +
    +
    +
    + ); +}; + +export default AdminLoginPage; diff --git a/src/pages/Admin/Auth/AdminProfilePage.tsx b/src/pages/Admin/Auth/AdminProfilePage.tsx new file mode 100644 index 0000000..863de23 --- /dev/null +++ b/src/pages/Admin/Auth/AdminProfilePage.tsx @@ -0,0 +1,697 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import ModalPrompt from "@/components/Modal/ModalPrompt"; +import { FaCloudUploadAlt } from "react-icons/fa"; +import Skeleton from "@/components/Skeleton/Skeleton"; + +let sdk = new MkdSDK(); + +const AdminProfilePage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + }) + .required(); + + const { dispatch } = React.useContext(AuthContext); + const [oldEmail, setOldEmail] = useState(""); + const [fileObj, setFileObj] = React.useState({}); + const [isModalOpen, setIsModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [oldPhoto, setOldPhoto] = useState(""); + const [isUploadedPhoto, setIsUploadedPhoto] = useState(false); + const [submitLoading, setSubmitLoading] = useState(false); + const [activeTab, setActiveTab] = useState("Profile"); + const [defaultValues, setDefaultValues] = useState({}); + const [loading, setLoading] = useState(true); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target, multiple = false) => { + setIsUploadedPhoto(true); + let tempFileObj = fileObj; + if (multiple) { + if (tempFileObj[field]) { + tempFileObj[field] = [ + ...tempFileObj[field], + { + file: target.files[0], + tempFile: { + url: URL.createObjectURL(target.files[0]), + name: target.files[0].name, + type: target.files[0].type, + }, + }, + ]; + } else { + tempFileObj[field] = [ + { + file: target.files[0], + tempFile: { + url: URL.createObjectURL(target.files[0]), + name: target.files[0].name, + type: target.files[0].type, + }, + }, + ]; + } + } else { + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + } + setFileObj({ ...tempFileObj }); + }; + + async function fetchData() { + setLoading(true); + try { + const result = await sdk.getProfile(); + if (!result.error) { + setDefaultValues(result); + setValue("email", result?.email); + setValue("first_name", result?.first_name); + setValue("last_name", result?.last_name); + setOldEmail(result?.email); + setOldPhoto(result?.photo); + dispatch({ + type: "UPDATE_PROFILE", + payload: result, + }); + setLoading(false); + } + } catch (error) { + tokenExpireError( + dispatch, + error.response.data.message + ? error.response.data.message + : error.message + ); + } + } + + const onSubmit = async (data) => { + if ( + defaultValues.email === data.email && + defaultValues.first_name === data.first_name && + defaultValues.last_name === data.last_name && + !isUploadedPhoto && + !data.password + ) { + closeModal(); + return showToast(globalDispatch, "No Changes Available", 1000); + } + + setDefaultValues(data); + try { + setSubmitLoading(true); + if (fileObj && fileObj["photo"] && fileObj["photo"]?.file) { + let formData = new FormData(); + formData.append("file", fileObj["photo"]?.file); + let uploadResult = await sdk.uploadImage(formData); + data["photo"] = uploadResult.url; + showToast(globalDispatch, "Profile Photo Updated", 1000); + } + + const result = await sdk.updateProfile({ + first_name: data.first_name || defaultValues?.first_name, + last_name: data.last_name || defaultValues?.last_name, + photo: data.photo || oldPhoto, + }); + + if (!result.error) { + showToast(globalDispatch, "Profile Updated", 4000); + closeModal(); + fetchData(); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + closeModal(); + } + if (oldEmail !== data.email) { + const emailresult = await sdk.updateEmail(data.email); + if (!emailresult.error) { + showToast(globalDispatch, "Email Updated", 1000); + } else { + if (emailresult.validation) { + const keys = Object.keys(emailresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: emailresult.validation[field], + }); + } + } + } + closeModal(); + } + + if (data.password?.length > 0) { + const passwordresult = await sdk.updatePassword(data.password); + if (!passwordresult.error) { + showToast(globalDispatch, "Password Updated", 2000); + } else { + if (passwordresult.validation) { + const keys = Object.keys(passwordresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: passwordresult.validation[field], + }); + } + } + } + } + data.photo = ""; + await fetchData(); + setSubmitLoading(false); + } catch (error) { + setSubmitLoading(false); + setError("email", { + type: "manual", + message: error.response.data.message + ? error.response.data.message + : error.message, + }); + tokenExpireError( + dispatch, + error.response.data.message + ? error.response.data.message + : error.message + ); + } + }; + + const onDeleteProfile = async () => { + setFileObj({}); + setOldPhoto(""); + setIsUploadedPhoto(true); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "profile", + }, + }); + + fetchData(); + }, []); + + const openModalEdit = () => { + setIsEditModalOpen(true); + }; + + const closeModal = () => { + setIsModalOpen(false); + setIsEditModalOpen(false); + setOldPhoto(defaultValues?.photo); + setFileObj({}); + setIsUploadedPhoto(false); + }; + + return ( +
    +
    +
    +
    setActiveTab("Profile")} + > + Profile +
    +
    setActiveTab("Security")} + > + Security +
    +
    +
    +
    + {/* Profile Tab */} + {activeTab === "Profile" && ( +
    +
    +

    + {errors.photo?.message} +

    +
    +
    +

    + Personal Details +

    + {!loading ? ( +

    + Edit +

    + ) : ( +
    + +
    + )} +
    + +
    +
    +

    + Profile Picture +

    + + {loading ? ( +
    +
    + +
    +
    + ) : defaultValues?.photo ? ( +
    + +
    + ) : ( +
    +
    + No Image +
    +
    + )} +
    +
    + +
    +
    +

    + First Name +

    +

    + {defaultValues?.first_name} +

    +
    +
    + +
    +
    +

    + Last Name +

    +

    + {defaultValues?.last_name} +

    +
    +
    +
    +
    +

    Email

    +

    + {oldEmail} +

    +
    +
    +
    +
    +
    + )} + + {/* Security tab */} + {activeTab === "Security" && ( +
    +
    +
    +
    + + +

    + {errors.password?.message} +

    +
    +
    + + Update + +
    +
    +
    +
    + )} + {isModalOpen && ( + + )} + {isEditModalOpen && ( + + )} +
    +
    + ); +}; + +export default AdminProfilePage; + +export const EditInfoModal = (props) => { + const { + title, + isOpen, + onClose, + handleSubmit, + onSubmit, + register, + submitLoading, + errors, + oldPhoto, + fileObj, + onDeleteProfile, + previewImage, + oldEmail, + } = props; + const [emailConfirm, setEmailConfirm] = useState(false); + const [values, setValues] = useState({ + email: "", + }); + const modalRef = React.useRef(null); + + useEffect(() => { + setValues({ ...values, email: oldEmail }); + setEmailConfirm(false); + }, [oldEmail]); + + const handleChange = (prop) => (event) => { + if (prop === "email") { + setValues({ ...values, [prop]: event.target.value }); + } + }; + + useEffect(() => { + const handleClickOutside = (event) => { + if (modalRef.current && !modalRef.current.contains(event.target)) { + onClose(); + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + } else { + document.removeEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isOpen, onClose]); + + return ( +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + {title} +
    + +
    +
    +
    + + {oldPhoto ? ( +
    +
    + + +
    + + X + +
    +
    +
    + ) : ( +
    +
    + {fileObj["photo"]?.tempURL ? ( + + ) : ( + + )} +
    +
    + )} +
    + + +

    + {errors?.id?.message} +

    +
    +
    + + +

    + {errors?.id?.message} +

    +
    + {emailConfirm && oldEmail !== values.email ? ( +
    +
    + + + +
    +
    +

    + We've sent an email to: {values?.email} +

    +

    +

    + In order to complete the email update click the + confirmation link. +

    +

    + (the link expires in 24 hours) +

    +
    +
    + ) : ( +
    + + +

    + {errors?.id?.message} +

    +
    + )} +
    + +
    + + + setEmailConfirm(true)} + > + Save + +
    +
    +
    +
    +
    +
    + ); +}; + diff --git a/src/pages/Admin/Auth/AdminResetPage.tsx b/src/pages/Admin/Auth/AdminResetPage.tsx new file mode 100644 index 0000000..17ee681 --- /dev/null +++ b/src/pages/Admin/Auth/AdminResetPage.tsx @@ -0,0 +1,167 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { Link } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { showToast } from "@/context/Global"; +import { InteractiveButton } from "@/components/InteractiveButton"; + +const AdminResetPage = () => { + const { dispatch } = React.useContext(AuthContext); + const [submitLoading, setSubmitLoading] = useState(false); + const search = window.location.search; + const params = new URLSearchParams(search); + const token = params.get("token"); + + const schema = yup + .object({ + code: yup.string().required(), + password: yup.string().required(), + confirmPassword: yup + .string() + .oneOf([yup.ref("password"), null], "Passwords must match"), + }) + .required(); + + const navigate = useNavigate(); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + try { + setSubmitLoading(true); + const result = await sdk.reset(token, data.code, data.password); + if (!result.error) { + showToast(dispatch, "Password Reset"); + setTimeout(() => { + navigate(`/admin/login`); + }, 2000); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + setSubmitLoading(false); + } catch (error) { + setSubmitLoading(false); + setError("code", { + type: "manual", + message: error.response.data.message + ? error.response.data.message + : error.message, + }); + tokenExpireError( + dispatch, + error.response.data.message + ? error.response.data.message + : error.message + ); + } + }; + + return ( + <> +
    +
    +
    + + +

    + {errors.code?.message} +

    +
    +
    + + +

    + {errors.password?.message} +

    +
    +
    + + +

    + {errors.confirmPassword?.message} +

    +
    +
    + + Reset Password + + + Login? + +
    +
    +

    + © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

    +
    + + ); +}; + +export default AdminResetPage; diff --git a/src/pages/Admin/Auth/AdminSignUpPage.tsx b/src/pages/Admin/Auth/AdminSignUpPage.tsx new file mode 100644 index 0000000..948dabe --- /dev/null +++ b/src/pages/Admin/Auth/AdminSignUpPage.tsx @@ -0,0 +1,175 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { Link, useLocation } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; +import { InteractiveButton } from "@/components/InteractiveButton"; +import { AuthContext } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; + +let sdk = new MkdSDK(); + +const SignUpPage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + password: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: GlobalDispatch } = React.useContext(GlobalContext); + + const [submitLoading, setSubmitLoading] = useState(false); + const location = useLocation(); + const searchParams = new URLSearchParams(location.search); + const redirect_uri = searchParams.get("redirect_uri"); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + try { + setSubmitLoading(true); + const result = await sdk.register(data.email, data.password, "admin"); + if (!result.error) { + dispatch({ + type: "LOGIN", + payload: result, + }); + showToast(GlobalDispatch, "Succesfully Registered", 4000, "success"); + navigate(redirect_uri ?? "/dashboard"); + } else { + setSubmitLoading(false); + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + setSubmitLoading(false); + showToast(GlobalDispatch, error?.message, 4000, "error"); + setError("email", { + type: "manual", + message: error?.response?.data?.message + ? error?.response?.data?.message + : error?.message, + }); + } + }; + + return ( +
    +
    +
    +
    +

    + Register +

    +
    + + + +

    + {errors.email?.message} +

    +
    + +
    + + + +

    + {errors.password?.message} +

    +
    + + + Register + +
    + +
    +
    +

    + Already have an account?{" "} + + Login{" "} + {" "} +

    +
    +
    + +

    + © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

    +
    +
    +
    +
    + ); +}; + +export default SignUpPage; diff --git a/src/pages/Admin/Edit/EditAdminProjectTablePage.tsx b/src/pages/Admin/Edit/EditAdminProjectTablePage.tsx new file mode 100644 index 0000000..173a540 --- /dev/null +++ b/src/pages/Admin/Edit/EditAdminProjectTablePage.tsx @@ -0,0 +1,504 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { useNavigate, useParams } from "react-router-dom"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { isImage, empty, isVideo, isPdf } from "@/utils/utils"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import BaasSDK from "@/utils/BaasSDK"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; + +let sdk = new MkdSDK(); +let baasSdk = new BaasSDK(); + +const EditProjectPage = ({ activeId, setSidebar }) => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + name: yup.string(), + slug: yup.string(), + secret: yup.string(), + api_domain: yup.string(), + api_domain_id: yup.string(), + frontend_domain: yup.string(), + frontend_domain_id: yup.string(), + wireframe_id: yup.string(), + api_deploy_status: yup.string(), + frontend_deploy_status: yup.string(), + configuration: yup.string(), + validations: yup.string(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + + const [name, setName] = useState(""); + const [slug, setSlug] = useState(""); + const [secret, setSecret] = useState(""); + const [api_domain, setApiDomain] = useState(0); + const [api_domain_id, setApiDomainId] = useState(0); + const [frontend_domain, setFrontendDomain] = useState(0); + const [frontend_domain_id, setFrontendDomainId] = useState(0); + const [wireframe_id, setWireframeId] = useState(0); + const [api_deploy_status, setApiDeployStatus] = useState(0); + const [frontend_deploy_status, setFrontendDeployStatus] = useState(0); + const [configuration, setConfiguration] = useState(""); + const [validations, setValidations] = useState(""); + const [id, setId] = useState(0); + const [isEditing, setIsEditing] = useState(false); + + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect( + function () { + (async function () { + try { + baasSdk.setTable("projects"); + const result = await baasSdk.callRestAPI({ id: activeId }, "GET"); + if (!result.error) { + setValue("name", result.model.name); + setValue("hostname", result.model.hostname); + setValue("slug", result.model.slug); + setValue("secret", result.model.secret); + setValue("api_domain", result.model.api_domain); + setValue("api_domain_id", result.model.api_domain_id); + setValue("frontend_domain", result.model.frontend_domain); + setValue("frontend_domain_id", result.model.frontend_domain_id); + setValue("wireframe_id", result.model.wireframe_id); + setValue("api_deploy_status", result.model.api_deploy_status); + setValue( + "frontend_deploy_status", + result.model.frontend_deploy_status + ); + setValue("configuration", result.model.configuration); + setValue("validations", result.model.validations); + + setName(result.model.name); + setHostname(result.model.hostname); + setSlug(result.model.slug); + setSecret(result.model.secret); + setApiDomain(result.model.api_domain); + setApiDomainId(result.model.api_domain_id); + setFrontendDomain(result.model.frontend_domain); + setFrontendDomainId(result.model.frontend_domain_id); + setWireframeId(result.model.wireframe_id); + setApiDeployStatus(result.model.api_deploy_status); + setFrontendDeployStatus(result.model.frontend_deploy_status); + setConfiguration(result.model.configuration); + setValidations(result.model.validations); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, + [activeId] + ); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (_data) => { + setIsEditing(true); + try { + baasSdk.setTable("projects"); + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + _data[item] = uploadResult.url; + } + const result = await baasSdk.callRestAPI( + { + id: activeId, + name: _data.name, + hostname: _data.hostname, + // slug: _data.slug, + // secret: _data.secret, + // api_domain: _data.api_domain, + // api_domain_id: _data.api_domain_id, + // frontend_domain: _data.frontend_domain, + // frontend_domain_id: _data.frontend_domain_id, + // wireframe_id: _data.wireframe_id, + // api_deploy_status: _data.api_deploy_status, + // frontend_deploy_status: _data.frontend_deploy_status, + // configuration: _data.configuration, + // validations: _data.validations, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/project"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("name", { + type: "manual", + message: error.message, + }); + } + setIsEditing(false); + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "project", + }, + }); + }, []); + + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Edit Project +
    +
    + + +
    +
    +
    +
    + + +

    {errors.name?.message}

    +
    +
    + + +

    + {errors.hostname?.message} +

    +
    + +
    + + +

    {errors.slug?.message}

    +
    + +
    + + +

    + {errors.secret?.message} +

    +
    + +
    + + +

    + {errors.api_domain?.message} +

    +
    + +
    + + +

    + {errors.api_domain_id?.message} +

    +
    + +
    + + +

    + {errors.frontend_domain?.message} +

    +
    + +
    + + +

    + {errors.frontend_domain_id?.message} +

    +
    + +
    + + +

    + {errors.wireframe_id?.message} +

    +
    + +
    + + +

    + {errors.api_deploy_status?.message} +

    +
    + +
    + + +

    + {errors.frontend_deploy_status?.message} +

    +
    + +
    + + +

    + {errors.configuration?.message} +

    +
    + +
    + + +

    + {errors.validations?.message} +

    +
    + {/* + */} +
    +
    + ); +}; + +export default EditProjectPage; diff --git a/src/pages/Admin/Edit/EditAdminSettingTablePage.tsx b/src/pages/Admin/Edit/EditAdminSettingTablePage.tsx new file mode 100644 index 0000000..9980f9f --- /dev/null +++ b/src/pages/Admin/Edit/EditAdminSettingTablePage.tsx @@ -0,0 +1,174 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate, useParams } from "react-router-dom"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { isImage, empty, isVideo, isPdf } from "@/utils/utils"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; + +let sdk = new MkdSDK(); + +const EditSettingPage = () => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + setting_key: yup.string(), + setting_value: yup.string(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + + const [setting_key, setSettingKey] = useState(""); + const [setting_value, setSettingValue] = useState(""); + const [id, setId] = useState(0); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + (async function () { + try { + sdk.setTable("setting"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setValue("setting_key", result.model.setting_key); + setValue("setting_value", result.model.setting_value); + + setSettingKey(result.model.setting_key); + setSettingValue(result.model.setting_value); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (_data) => { + try { + sdk.setTable("setting"); + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + _data[item] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + + setting_key: _data.setting_key, + setting_value: _data.setting_value, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/setting"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("setting_key", { + type: "manual", + message: error.message, + }); + } + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "setting", + }, + }); + }, []); + + return ( +
    +

    Edit Setting

    +
    +
    + + +

    + {errors.setting_key?.message} +

    +
    + +
    + + +

    + {errors.setting_value?.message} +

    +
    + + +
    +
    + ); +}; + +export default EditSettingPage; diff --git a/src/pages/Admin/Edit/EditAdminSowTablePage.tsx b/src/pages/Admin/Edit/EditAdminSowTablePage.tsx new file mode 100644 index 0000000..e96b9d5 --- /dev/null +++ b/src/pages/Admin/Edit/EditAdminSowTablePage.tsx @@ -0,0 +1,368 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { GlobalContext, showToast } from "@/context/Global"; +import { useNavigate, useParams } from "react-router-dom"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import { isImage, empty, isVideo, isPdf } from "@/utils/utils"; + +let sdk = new MkdSDK(); + +const EditSowPage = ({ activeId, setSidebar }) => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + name: yup.string(), + transcripts: yup.string(), + requirements: yup.string().nullable(), + breakdown: yup.string().nullable(), + presentation_code: yup.string().nullable(), + has_folder: yup.string(), + development_schedule: yup.string().nullable(), + status: yup.string(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + + const [name, setName] = useState(""); + const [transcripts, setTranscripts] = useState(""); + const [requirements, setRequirements] = useState(""); + const [breakdown, setBreakdown] = useState(""); + const [presentation_code, setPresentationCode] = useState(""); + const [has_folder, setHasFolder] = useState(""); + const [development_schedule, setDevelopmentSchedule] = useState(""); + const [status, setStatus] = useState(""); + const [id, setId] = useState(0); + const [isEditing, setIsEditing] = useState(false); + + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect( + function () { + (async function () { + try { + sdk.setTable("sow"); + const result = await sdk.callRestAPI({ id: activeId }, "GET"); + if (!result.error) { + setValue("name", result.model.name); + setValue("transcripts", result.model.transcripts); + setValue("requirements", result.model.requirements); + setValue("breakdown", result.model.breakdown); + setValue("presentation_code", result.model.presentation_code); + setValue("has_folder", result.model.has_folder); + setValue("development_schedule", result.model.development_schedule); + setValue("status", result.model.status); + + setName(result.model.name); + setTranscripts(result.model.transcripts); + setRequirements(result.model.requirements); + setBreakdown(result.model.breakdown); + setPresentationCode(result.model.presentation_code); + setHasFolder(result.model.has_folder); + setDevelopmentSchedule(result.model.development_schedule); + setStatus(result.model.status); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, + [activeId] + ); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (_data) => { + setIsEditing(true); + try { + sdk.setTable("sow"); + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + _data[item] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: activeId, + + name: _data.name, + transcripts: _data.transcripts, + requirements: _data.requirements, + breakdown: _data.breakdown, + presentation_code: _data.presentation_code, + has_folder: _data.has_folder, + development_schedule: _data.development_schedule, + status: _data.status, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/requirements"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("name", { + type: "manual", + message: error.message, + }); + } + setIsEditing(false); + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "sow", + }, + }); + }, []); + + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Edit SOW +
    +
    + + +
    +
    +
    +
    + + +

    {errors.name?.message}

    +
    + +
    + + +

    + {errors.transcripts?.message} +

    +
    + +
    + + +

    + {errors.requirements?.message} +

    +
    + +
    + + +

    + {errors.breakdown?.message} +

    +
    + +
    + + +

    + {errors.presentation_code?.message} +

    +
    + +
    + + + +

    + {errors.has_folder?.message} +

    +
    + +
    + + +

    + {errors.development_schedule?.message} +

    +
    + +
    + + + +

    + {errors.status?.message} +

    +
    + + {/* */} +
    +
    + ); +}; + +export default EditSowPage; diff --git a/src/pages/Admin/Edit/EditAdminUserPage.tsx b/src/pages/Admin/Edit/EditAdminUserPage.tsx new file mode 100644 index 0000000..5edc0eb --- /dev/null +++ b/src/pages/Admin/Edit/EditAdminUserPage.tsx @@ -0,0 +1,268 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import { useNavigate, useParams } from "react-router-dom"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import { GlobalContext, showToast } from "@/context/Global"; + +let sdk = new MkdSDK(); + +const EditAdminUserPage = ({ activeId, setSidebar }) => { + const schema = yup + .object({ + email: yup.string().email().required(), + password: yup.string(), + role: yup.string(), + }) + .required(); + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const navigate = useNavigate(); + const params = useParams(); + const [oldEmail, setOldEmail] = useState(""); + const [id, setId] = useState(0); + const [isEditing, setIsEditing] = useState(false); + + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const selectRole = ["admin", "employee"]; + const selectStatus = [ + { key: "0", value: "Inactive" }, + { key: "2", value: "Suspend" }, + { key: "1", value: "Active" }, + ]; + + const onSubmit = async (data) => { + setIsEditing(true); + try { + if (oldEmail !== data.email) { + const emailresult = await sdk.updateEmailByAdmin(data.email, activeId); + if (!emailresult.error) { + showToast(globalDispatch, "Email Updated", 1000); + } else { + if (emailresult.validation) { + const keys = Object.keys(emailresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: emailresult.validation[field], + }); + } + } + } + } + + if (data.password.length > 0) { + const passwordresult = await sdk.updatePasswordByAdmin( + data.password, + activeId + ); + if (!passwordresult.error) { + showToast(globalDispatch, "Password Updated", 2000); + } else { + if (passwordresult.validation) { + const keys = Object.keys(passwordresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: passwordresult.validation[field], + }); + } + } + } + } + + sdk.setTable("user"); + + const result = await sdk.callRestAPI( + { activeId, email: data.email, role: data.role, status: data.status }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Added", 4000); + navigate("/admin/users"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + setIsEditing(false); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "users", + }, + }); + + (async function () { + try { + sdk.setTable("user"); + const result = await sdk.callRestAPI({ id: activeId }, "GET"); + + if (!result.error) { + setValue("email", result.model.email); + setValue("role", result.model.role); + setValue("status", result.model.status); + setOldEmail(result.model.email); + setId(result.model.id); + } + } catch (error) { + console.log("Error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, [activeId]); + return ( +
    +
    +
    + setSidebar(false)} + xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + > + + + Edit User +
    +
    + + +
    +
    +
    +
    + + +

    {errors.email?.message}

    +
    +
    + + +
    +
    + + +
    +
    + + +

    + {errors.password?.message} +

    +
    + {/* */} +
    +
    + ); +}; + +export default EditAdminUserPage; diff --git a/src/pages/Admin/Edit/EditAdminWireframeTablePage.tsx b/src/pages/Admin/Edit/EditAdminWireframeTablePage.tsx new file mode 100644 index 0000000..f84877b --- /dev/null +++ b/src/pages/Admin/Edit/EditAdminWireframeTablePage.tsx @@ -0,0 +1,240 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "@/utils/MkdSDK"; +import TreeSDK from "@/utils/TreeSDK"; +import { useNavigate, useParams } from "react-router-dom"; +import { GlobalContext, showToast } from "@/context/Global"; +import { AuthContext, tokenExpireError } from "@/context/Auth"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import { isImage, empty, isVideo, isPdf } from "@/utils/utils"; + +let sdk = new MkdSDK(); + +const EditWireframePage = () => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + name: yup.string(), + config: yup.string(), + sow_id: yup.string(), + status: yup.string(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + + const [name, setName] = useState(""); + const [config, setConfig] = useState(""); + const [sow_id, setSowId] = useState(0); + const [status, setStatus] = useState(0); + const [sows, setSows] = useState([]); + const [id, setId] = useState(0); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + (async function () { + try { + sdk.setTable("wireframe"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setValue("name", result.model.name); + setValue("config", result.model.config); + setValue("sow_id", result.model.sow_id); + setValue("status", result.model.status); + + setName(result.model.name); + setConfig(result.model.config); + setSowId(result.model.sow_id); + setStatus(result.model.status); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (_data) => { + try { + sdk.setTable("wireframe"); + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + _data[item] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + + name: _data.name, + config: _data.config, + sow_id: _data.sow_id, + status: _data.status, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/build"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("name", { + type: "manual", + message: error.message, + }); + } + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "wireframe", + }, + }); + }, []); + + React.useEffect(() => { + (async () => { + new TreeSDK() + .getList("sow") + .then((res) => setSows(res.list)) + .catch((err) => console.log(err)); + })(); + }, []); + + return ( +
    +

    Edit Wireframe

    +
    +
    + + +

    {errors.name?.message}

    +
    + +
    + + +

    + {errors.config?.message} +

    +
    + +
    + + + +

    + {errors.sow_id?.message} +

    +
    + +
    + + + +

    + {errors.status?.message} +

    +
    + + +
    +
    + ); +}; + +export default EditWireframePage; diff --git a/src/pages/Admin/Edit/EditWireframePage.tsx b/src/pages/Admin/Edit/EditWireframePage.tsx new file mode 100644 index 0000000..eb54964 --- /dev/null +++ b/src/pages/Admin/Edit/EditWireframePage.tsx @@ -0,0 +1,155 @@ +import React, { useState } from "react"; + +import { useParams, useLocation, useNavigate } from "react-router-dom"; +import { Views } from "@/context/Global"; + +import { EditWireframeTabTypes } from "@/utils/constants"; +import { EditWireframeTabs } from "@/components/EditWireframeTabs"; +import { LazyLoad } from "@/components/LazyLoad"; +// import SkeletonLoader from "@/components/Skeleton/Skeleton"; + +import { ModalPrompt } from "@/components/Modal"; +import { useContexts } from "@/hooks/useContexts"; +import { useSDK } from "@/hooks/useSDK"; + +const saveRestriction = [ + // "Requirements", + // "Model", + // "API", + // "Web/React", + // "IOS", + "Android", + // "Deployment" +]; + +const EditWireframePage = () => { + const { sdk } = useSDK(); + const { authDispatch, globalDispatch, setGlobalState } = useContexts(); + + const [sow, setSow] = useState({}); + const [activeTab, setActiveTab] = useState(EditWireframeTabTypes?.API); + const [requirementIsReady, setRequirementIsReady] = useState(false); + const [prevConfig, setPrevConfig] = useState(null); + const [isChanged, setIsChanged] = useState(false); + const [openSavePrompt, setOpenSavePrompt] = useState(false); + const navigate = useNavigate(); + const location = useLocation(); + + const params = useParams(); + + React.useEffect(() => { + globalDispatch({ + type: "SHOW_BACKBUTTON", + payload: { showBackButton: true }, + }); + + return () => { + globalDispatch({ + type: "SHOW_BACKBUTTON", + payload: { showBackButton: false }, + }); + }; + }, []); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "wireframe", + }, + }); + }, []); + + const updateUrlWithTab = (tab: string) => { + const queryParams = new URLSearchParams(location.search); + queryParams.set("tab", tab); + navigate({ search: queryParams.toString() }); + }; + + const handleClick = (value: string) => { + setActiveTab(value); + updateUrlWithTab(value); + }; + + React.useEffect(() => { + const queryParams = new URLSearchParams(location.search); + const tab = queryParams.get("tab"); + if (tab) { + setActiveTab(tab); + } + }, [location.search]); + + React.useEffect(() => { + if (activeTab === EditWireframeTabTypes?.API) { + setGlobalState("view", Views.RouteList); + } + }, [activeTab]); + + // if (!requirementIsReady) { + // return ; + // } + + return ( +
    + + + + +
    + {activeTab === EditWireframeTabTypes.Requirements && ( + + <> + + )} + + {activeTab === EditWireframeTabTypes?.API && ( + + <> +