Compare commits
8 Commits
c5f534a8f4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 6133a4e339 | |||
| 042a7155b6 | |||
| 84639713a8 | |||
| a86245b7bd | |||
| 434a8b6c6d | |||
| ff11b80b36 | |||
| 70c6176071 | |||
| c26b96fa9b |
BIN
Nearle_Full_API_Documentation.docx
Normal file
BIN
Nearle_Full_API_Documentation.docx
Normal file
Binary file not shown.
470
package-lock.json
generated
470
package-lock.json
generated
@@ -15,14 +15,14 @@
|
|||||||
"tailwind-merge": "^3.5.0"
|
"tailwind-merge": "^3.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^9.11.1",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.18",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
"eslint-plugin-react-refresh": "^0.4.12",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"vite": "^5.2.0"
|
"vite": "^5.2.0"
|
||||||
@@ -743,65 +743,100 @@
|
|||||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
"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,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"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,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "2.1.4",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
|
||||||
"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
|
"integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.14.0",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"espree": "^9.6.0",
|
"espree": "^10.0.1",
|
||||||
"globals": "^13.19.0",
|
"globals": "^14.0.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.2.1",
|
"import-fresh": "^3.2.1",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.1",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.5",
|
||||||
"strip-json-comments": "^3.1.1"
|
"strip-json-comments": "^3.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "10.0.1",
|
"version": "9.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz",
|
||||||
"integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
|
"integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://eslint.org/donate"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"eslint": "^10.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"eslint": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@eslint/object-schema": {
|
||||||
"version": "0.13.0",
|
"version": "2.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
|
||||||
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
|
"integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
|
||||||
"deprecated": "Use @eslint/config-array instead",
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@eslint/plugin-kit": {
|
||||||
|
"version": "0.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
|
||||||
|
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanwhocodes/object-schema": "^2.0.3",
|
"@eslint/core": "^0.13.0",
|
||||||
"debug": "^4.3.1",
|
"levn": "^0.4.1"
|
||||||
"minimatch": "^3.0.5"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.10.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
|
||||||
|
"version": "0.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
|
||||||
|
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.15"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/module-importer": {
|
"node_modules/@humanwhocodes/module-importer": {
|
||||||
@@ -818,13 +853,19 @@
|
|||||||
"url": "https://github.com/sponsors/nzakas"
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/object-schema": {
|
"node_modules/@humanwhocodes/retry": {
|
||||||
"version": "2.0.3",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
|
||||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
|
||||||
"deprecated": "Use @eslint/object-schema instead",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause"
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
@@ -1323,6 +1364,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"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,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.2.14",
|
"version": "19.2.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||||
@@ -1343,13 +1391,6 @@
|
|||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ungap/structured-clone": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/@vitejs/plugin-react": {
|
"node_modules/@vitejs/plugin-react": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
||||||
@@ -1458,6 +1499,19 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/anymatch/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/arg": {
|
"node_modules/arg": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||||
@@ -1823,19 +1877,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/doctrine": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"esutils": "^2.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.344",
|
"version": "1.5.344",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz",
|
||||||
@@ -1916,45 +1957,43 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "8.57.1",
|
"version": "9.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz",
|
||||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
"integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==",
|
||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.11.0",
|
||||||
"@eslint/eslintrc": "^2.1.4",
|
"@eslint/config-array": "^0.18.0",
|
||||||
"@eslint/js": "8.57.1",
|
"@eslint/core": "^0.6.0",
|
||||||
"@humanwhocodes/config-array": "^0.13.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
|
"@eslint/js": "9.11.1",
|
||||||
|
"@eslint/plugin-kit": "^0.2.0",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
|
"@humanwhocodes/retry": "^0.3.0",
|
||||||
"@nodelib/fs.walk": "^1.2.8",
|
"@nodelib/fs.walk": "^1.2.8",
|
||||||
"@ungap/structured-clone": "^1.2.0",
|
"@types/estree": "^1.0.6",
|
||||||
|
"@types/json-schema": "^7.0.15",
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.2",
|
"cross-spawn": "^7.0.2",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"doctrine": "^3.0.0",
|
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^7.2.2",
|
"eslint-scope": "^8.0.2",
|
||||||
"eslint-visitor-keys": "^3.4.3",
|
"eslint-visitor-keys": "^4.0.0",
|
||||||
"espree": "^9.6.1",
|
"espree": "^10.1.0",
|
||||||
"esquery": "^1.4.2",
|
"esquery": "^1.5.0",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"file-entry-cache": "^6.0.1",
|
"file-entry-cache": "^8.0.0",
|
||||||
"find-up": "^5.0.0",
|
"find-up": "^5.0.0",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"globals": "^13.19.0",
|
|
||||||
"graphemer": "^1.4.0",
|
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"imurmurhash": "^0.1.4",
|
"imurmurhash": "^0.1.4",
|
||||||
"is-glob": "^4.0.0",
|
"is-glob": "^4.0.0",
|
||||||
"is-path-inside": "^3.0.3",
|
"is-path-inside": "^3.0.3",
|
||||||
"js-yaml": "^4.1.0",
|
|
||||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||||
"levn": "^0.4.1",
|
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.2",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1966,39 +2005,47 @@
|
|||||||
"eslint": "bin/eslint.js"
|
"eslint": "bin/eslint.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://eslint.org/donate"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"jiti": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react-hooks": {
|
"node_modules/eslint-plugin-react-hooks": {
|
||||||
"version": "4.6.2",
|
"version": "5.1.0-rc.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc.0.tgz",
|
||||||
"integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
|
"integrity": "sha512-xBc+mRT2KSyzKm78GyaOFPyF4EnSRfTSmre88Ak8jG1HnpNGEiHETbCuXih8Xl796DryrJej/8IdW4oQ+m5kPg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
"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": {
|
"node_modules/eslint-plugin-react-refresh": {
|
||||||
"version": "0.4.26",
|
"version": "0.4.12",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz",
|
||||||
"integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
|
"integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": ">=8.40"
|
"eslint": ">=7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "7.2.2",
|
"version": "8.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||||
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
|
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2006,7 +2053,7 @@
|
|||||||
"estraverse": "^5.2.0"
|
"estraverse": "^5.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
@@ -2025,29 +2072,45 @@
|
|||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/@eslint/js": {
|
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
||||||
"version": "8.57.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "9.6.1",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||||
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.9.0",
|
"acorn": "^8.15.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/espree/node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
@@ -2179,16 +2242,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||||
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
|
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flat-cache": "^3.0.4"
|
"flat-cache": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": ">=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
@@ -2222,18 +2285,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flat-cache": {
|
"node_modules/flat-cache": {
|
||||||
"version": "3.2.0",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
|
||||||
"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
|
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
"keyv": "^4.5.3",
|
"keyv": "^4.5.4"
|
||||||
"rimraf": "^3.0.2"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flatted": {
|
"node_modules/flatted": {
|
||||||
@@ -2257,13 +2319,6 @@
|
|||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -2299,28 +2354,6 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
|
||||||
"version": "7.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
|
||||||
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"fs.realpath": "^1.0.0",
|
|
||||||
"inflight": "^1.0.4",
|
|
||||||
"inherits": "2",
|
|
||||||
"minimatch": "^3.1.1",
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
@@ -2335,28 +2368,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "13.24.0",
|
"version": "14.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||||
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
|
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
|
||||||
"type-fest": "^0.20.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/has-flag": {
|
"node_modules/has-flag": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
@@ -2417,25 +2440,6 @@
|
|||||||
"node": ">=0.8.19"
|
"node": ">=0.8.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
|
||||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@@ -2702,6 +2706,19 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/micromatch/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.5",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||||
@@ -2797,16 +2814,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@@ -2880,16 +2887,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-key": {
|
"node_modules/path-key": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
@@ -2915,13 +2912,13 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.2",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
@@ -3205,6 +3202,19 @@
|
|||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readdirp/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.12",
|
"version": "1.22.12",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
|
||||||
@@ -3248,23 +3258,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rimraf": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
|
||||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"rimraf": "bin.js"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.60.2",
|
"version": "4.60.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz",
|
||||||
@@ -3553,19 +3546,6 @@
|
|||||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@@ -3599,19 +3579,6 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/type-fest": {
|
|
||||||
"version": "0.20.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
|
||||||
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "(MIT OR CC0-1.0)",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||||
@@ -3746,13 +3713,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
|||||||
@@ -17,14 +17,14 @@
|
|||||||
"tailwind-merge": "^3.5.0"
|
"tailwind-merge": "^3.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^9.11.1",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.18",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
"eslint-plugin-react-refresh": "^0.4.12",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"vite": "^5.2.0"
|
"vite": "^5.2.0"
|
||||||
|
|||||||
BIN
scratch/docx_content.txt
Normal file
BIN
scratch/docx_content.txt
Normal file
Binary file not shown.
233
scratch/docx_content_utf8.txt
Normal file
233
scratch/docx_content_utf8.txt
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
0: Nearle Mobile API – Full GraphQL Documentation
|
||||||
|
1: GetCustomerLocations
|
||||||
|
2: REST Params:
|
||||||
|
3: {"customerid": 6060}
|
||||||
|
4: GraphQL Query:
|
||||||
|
5: query GetCustomerLocations($customerid: bigint!) {
|
||||||
|
6: customer_locations(where: { customerid: { _eq: $customerid } }) {
|
||||||
|
7: locationid
|
||||||
|
8: latitude
|
||||||
|
9: longitude
|
||||||
|
10: address
|
||||||
|
11: }
|
||||||
|
12: }
|
||||||
|
13: GraphQL Variables:
|
||||||
|
14: {"customerid": 6060}
|
||||||
|
15: GetCustomerOrdersV3
|
||||||
|
16: REST Params:
|
||||||
|
17: {"customerid":6060,"tenantid":1087,"moduleid":2,"fromdate":"2026-01-01T00:00:00","todate":"2026-12-31T23:59:59","orderstatus":"delivered","keyword":"%pizza%","limit":10,"offset":0}
|
||||||
|
18: GraphQL Query:
|
||||||
|
19: query GetCustomerOrders($customerid: bigint!, $tenantid: bigint!, $moduleid: bigint!, $fromdate: timestamptz!, $todate: timestamptz!, $orderstatus: String!, $keyword: String, $limit: Int!, $offset: Int!) {
|
||||||
|
20: orders(
|
||||||
|
21: where: {
|
||||||
|
22: customerid: { _eq: $customerid }
|
||||||
|
23: tenantid: { _eq: $tenantid }
|
||||||
|
24: moduleid: { _eq: $moduleid }
|
||||||
|
25: orderstatus: { _eq: $orderstatus }
|
||||||
|
26: orderdate: { _gte: $fromdate, _lte: $todate }
|
||||||
|
27: _or: [{ orderid: { _ilike: $keyword } }]
|
||||||
|
28: }
|
||||||
|
29: limit: $limit
|
||||||
|
30: offset: $offset
|
||||||
|
31: ) {
|
||||||
|
32: orderid
|
||||||
|
33: orderstatus
|
||||||
|
34: orderamount
|
||||||
|
35: }
|
||||||
|
36: }
|
||||||
|
37: GraphQL Variables:
|
||||||
|
38: {"customerid":6060,"tenantid":1087,"moduleid":2,"fromdate":"2026-01-01T00:00:00","todate":"2026-12-31T23:59:59","orderstatus":"delivered","keyword":"%pizza%","limit":10,"offset":0}
|
||||||
|
39: GetCustomer
|
||||||
|
40: REST Params:
|
||||||
|
41: {"customerid":6060}
|
||||||
|
42: GraphQL Query:
|
||||||
|
43: query GetCustomer($customerid: bigint!) {
|
||||||
|
44: customers(where: { customerid: { _eq: $customerid } }) {
|
||||||
|
45: customerid
|
||||||
|
46: name
|
||||||
|
47: contactno
|
||||||
|
48: }
|
||||||
|
49: }
|
||||||
|
50: GraphQL Variables:
|
||||||
|
51: {"customerid":6060}
|
||||||
|
52: GetCustomerRequests
|
||||||
|
53: REST Params:
|
||||||
|
54: {"customerid":6060,"limit":10,"offset":0}
|
||||||
|
55: GraphQL Query:
|
||||||
|
56: query GetCustomerRequests($customerid: bigint!, $limit: Int!, $offset: Int!) {
|
||||||
|
57: customer_requests(where: { customerid: { _eq: $customerid } }, limit: $limit, offset: $offset) {
|
||||||
|
58: requestid
|
||||||
|
59: status
|
||||||
|
60: }
|
||||||
|
61: }
|
||||||
|
62: GraphQL Variables:
|
||||||
|
63: {"customerid":6060,"limit":10,"offset":0}
|
||||||
|
64: GetProductSubcategories
|
||||||
|
65: REST Params:
|
||||||
|
66: {"categoryid":1001}
|
||||||
|
67: GraphQL Query:
|
||||||
|
68: query GetProductSubcategories($categoryid: bigint!) {
|
||||||
|
69: app_subcategory(where: { categoryid: { _eq: $categoryid } }) {
|
||||||
|
70: subcategoryid
|
||||||
|
71: subcategoryname
|
||||||
|
72: }
|
||||||
|
73: }
|
||||||
|
74: GraphQL Variables:
|
||||||
|
75: {"categoryid":1001}
|
||||||
|
76: GetAppCategories
|
||||||
|
77: REST Params:
|
||||||
|
78: {}
|
||||||
|
79: GraphQL Query:
|
||||||
|
80: query GetAppCategories {
|
||||||
|
81: app_category {
|
||||||
|
82: categoryid
|
||||||
|
83: categoryname
|
||||||
|
84: }
|
||||||
|
85: }
|
||||||
|
86: GraphQL Variables:
|
||||||
|
87: {}
|
||||||
|
88: GetProductVariants
|
||||||
|
89: REST Params:
|
||||||
|
90: {"tenantid":1087,"subcategoryid":14}
|
||||||
|
91: GraphQL Query:
|
||||||
|
92: query GetProductVariants($tenantid: bigint!, $subcategoryid: bigint!) {
|
||||||
|
93: product_variants(where: { tenantid: { _eq: $tenantid }, subcategoryid: { _eq: $subcategoryid } }) {
|
||||||
|
94: variantid
|
||||||
|
95: productname
|
||||||
|
96: price
|
||||||
|
97: }
|
||||||
|
98: }
|
||||||
|
99: GraphQL Variables:
|
||||||
|
100: {"tenantid":1087,"subcategoryid":14}
|
||||||
|
101: GetTenantPromotions
|
||||||
|
102: REST Params:
|
||||||
|
103: {"tenantid":1087,"locationid":1}
|
||||||
|
104: GraphQL Query:
|
||||||
|
105: query GetTenantPromotions($tenantid: bigint!, $locationid: bigint!) {
|
||||||
|
106: promotions(where: { tenantid: { _eq: $tenantid }, locationid: { _eq: $locationid } }) {
|
||||||
|
107: promotionid
|
||||||
|
108: title
|
||||||
|
109: }
|
||||||
|
110: }
|
||||||
|
111: GraphQL Variables:
|
||||||
|
112: {"tenantid":1087,"locationid":1}
|
||||||
|
113: GetAppConfig
|
||||||
|
114: REST Params:
|
||||||
|
115: {"configid":15}
|
||||||
|
116: GraphQL Query:
|
||||||
|
117: query GetAppConfig($configid: bigint!) {
|
||||||
|
118: app_config(where: { configid: { _eq: $configid } }) {
|
||||||
|
119: configkey
|
||||||
|
120: configvalue
|
||||||
|
121: }
|
||||||
|
122: }
|
||||||
|
123: GraphQL Variables:
|
||||||
|
124: {"configid":15}
|
||||||
|
125: searchcustomers
|
||||||
|
126: REST Params:
|
||||||
|
127: {"tenantid":1087,"keyword":"%john%"}
|
||||||
|
128: GraphQL Query:
|
||||||
|
129: query SearchCustomers($tenantid: bigint!, $keyword: String!) {
|
||||||
|
130: customers(where: { tenantid: { _eq: $tenantid }, name: { _ilike: $keyword } }) {
|
||||||
|
131: customerid
|
||||||
|
132: name
|
||||||
|
133: }
|
||||||
|
134: }
|
||||||
|
135: GraphQL Variables:
|
||||||
|
136: {"tenantid":1087,"keyword":"%john%"}
|
||||||
|
137: getTenantorders
|
||||||
|
138: REST Params:
|
||||||
|
139: {}
|
||||||
|
140: GraphQL Query:
|
||||||
|
141: query GetTenantOrders {
|
||||||
|
142: orders {
|
||||||
|
143: orderid
|
||||||
|
144: tenantid
|
||||||
|
145: }
|
||||||
|
146: }
|
||||||
|
147: GraphQL Variables:
|
||||||
|
148: {}
|
||||||
|
149: getstaff
|
||||||
|
150: REST Params:
|
||||||
|
151: {"tenantid":1087}
|
||||||
|
152: GraphQL Query:
|
||||||
|
153: query GetStaff($tenantid: bigint!) {
|
||||||
|
154: staff(where: { tenantid: { _eq: $tenantid } }) {
|
||||||
|
155: staffid
|
||||||
|
156: name
|
||||||
|
157: }
|
||||||
|
158: }
|
||||||
|
159: GraphQL Variables:
|
||||||
|
160: {"tenantid":1087}
|
||||||
|
161: GetTenantInfo
|
||||||
|
162: REST Params:
|
||||||
|
163: {"tenantid":1079}
|
||||||
|
164: GraphQL Query:
|
||||||
|
165: query GetTenantInfo($tenantid: bigint!) {
|
||||||
|
166: tenants(where: { tenantid: { _eq: $tenantid } }) {
|
||||||
|
167: tenantname
|
||||||
|
168: city
|
||||||
|
169: }
|
||||||
|
170: }
|
||||||
|
171: GraphQL Variables:
|
||||||
|
172: {"tenantid":1079}
|
||||||
|
173: getTenantlocations
|
||||||
|
174: REST Params:
|
||||||
|
175: {"tenantid":1}
|
||||||
|
176: GraphQL Query:
|
||||||
|
177: query GetTenantLocations($tenantid: bigint!) {
|
||||||
|
178: tenant_locations(where: { tenantid: { _eq: $tenantid } }) {
|
||||||
|
179: locationid
|
||||||
|
180: locationname
|
||||||
|
181: }
|
||||||
|
182: }
|
||||||
|
183: GraphQL Variables:
|
||||||
|
184: {"tenantid":1}
|
||||||
|
185: getapplocations
|
||||||
|
186: REST Params:
|
||||||
|
187: {}
|
||||||
|
188: GraphQL Query:
|
||||||
|
189: query GetAppLocations {
|
||||||
|
190: app_location {
|
||||||
|
191: applocationid
|
||||||
|
192: locationname
|
||||||
|
193: }
|
||||||
|
194: }
|
||||||
|
195: GraphQL Variables:
|
||||||
|
196: {}
|
||||||
|
197: getsubcategory
|
||||||
|
198: REST Params:
|
||||||
|
199: {"moduleid":6,"categoryid":1}
|
||||||
|
200: GraphQL Query:
|
||||||
|
201: query GetSubCategory($moduleid: bigint!, $categoryid: bigint!) {
|
||||||
|
202: app_subcategory(where: { categoryid: { _eq: $categoryid }, category: { modules: { moduleid: { _eq: $moduleid } } } }) {
|
||||||
|
203: subcategoryid
|
||||||
|
204: subcategoryname
|
||||||
|
205: }
|
||||||
|
206: }
|
||||||
|
207: GraphQL Variables:
|
||||||
|
208: {"moduleid":6,"categoryid":1}
|
||||||
|
209: GetPartners
|
||||||
|
210: REST Params:
|
||||||
|
211: {"applocationid":1,"partnerid":44,"limit":10,"offset":0}
|
||||||
|
212: GraphQL Query:
|
||||||
|
213: query GetPartners($applocationid: bigint!, $partnerid: bigint, $limit: Int!, $offset: Int!) {
|
||||||
|
214: partners(where: { applocationid: { _eq: $applocationid }, partnerid: { _eq: $partnerid } }, limit: $limit, offset: $offset) {
|
||||||
|
215: partnerid
|
||||||
|
216: name
|
||||||
|
217: }
|
||||||
|
218: }
|
||||||
|
219: GraphQL Variables:
|
||||||
|
220: {"applocationid":1,"partnerid":44,"limit":10,"offset":0}
|
||||||
|
221: GetlocationsConfig
|
||||||
|
222: REST Params:
|
||||||
|
223: {}
|
||||||
|
224: GraphQL Query:
|
||||||
|
225: query GetLocationConfig {
|
||||||
|
226: app_locationconfigs {
|
||||||
|
227: applocationid
|
||||||
|
228: configkey
|
||||||
|
229: }
|
||||||
|
230: }
|
||||||
|
231: GraphQL Variables:
|
||||||
|
232: {}
|
||||||
15
scratch/extract_docx.py
Normal file
15
scratch/extract_docx.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import docx
|
||||||
|
import json
|
||||||
|
|
||||||
|
def extract_docx_content(file_path):
|
||||||
|
doc = docx.Document(file_path)
|
||||||
|
full_text = []
|
||||||
|
for para in doc.paragraphs:
|
||||||
|
full_text.append(para.text)
|
||||||
|
return "\n".join(full_text)
|
||||||
|
|
||||||
|
content = extract_docx_content('Nearle_Full_API_Documentation.docx')
|
||||||
|
with open('scratch/docx_content_utf8.txt', 'w', encoding='utf-8') as f:
|
||||||
|
lines = content.split('\n')
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
f.write(f"{i}: {line}\n")
|
||||||
176
src/App.jsx
176
src/App.jsx
@@ -1,116 +1,116 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo, useEffect } from 'react';
|
||||||
|
import { Menu, Layers } from 'lucide-react';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
import EndpointViewer from './components/EndpointViewer';
|
import EndpointViewer from './components/EndpointViewer';
|
||||||
import { topics } from './data/apiData';
|
import Introduction from './components/Introduction';
|
||||||
import { ArrowRight, Code2, Zap, Users, ShoppingCart, Home, Box, Link2 } from 'lucide-react';
|
import ThemeToggle from './components/ThemeToggle';
|
||||||
|
import { graphqlTopics, GRAPHQL_BASE_URL } from './data/apiData';
|
||||||
|
import { restTopics, REST_BASE_URL } from './data/restTopics';
|
||||||
|
|
||||||
const topicIcons = {
|
const processTopics = (topics, baseUrl, type) =>
|
||||||
users: Users,
|
topics.map(t => ({ ...t, baseUrl, type, uniqueId: `${type}-${t.id}` }));
|
||||||
orders: ShoppingCart,
|
|
||||||
tenants: Home,
|
const allGraphql = processTopics(graphqlTopics, GRAPHQL_BASE_URL, 'graphql');
|
||||||
products: Box,
|
const allRest = processTopics(restTopics, REST_BASE_URL, 'rest');
|
||||||
locations: Link2,
|
|
||||||
partners: Users,
|
function filterTopics(topics, q) {
|
||||||
};
|
if (!q) return topics;
|
||||||
|
return topics.filter(t =>
|
||||||
|
t.name.toLowerCase().includes(q) ||
|
||||||
|
(t.description || '').toLowerCase().includes(q) ||
|
||||||
|
t.endpoints.some(e =>
|
||||||
|
e.name.toLowerCase().includes(q) ||
|
||||||
|
e.url.toLowerCase().includes(q) ||
|
||||||
|
(e.description || '').toLowerCase().includes(q)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [activeTopic, setActiveTopic] = useState(null);
|
const [activeTopic, setActiveTopic] = useState(null);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
const [dark, setDark] = useState(() => {
|
||||||
|
if (typeof window === 'undefined') return false;
|
||||||
|
const saved = localStorage.getItem('theme');
|
||||||
|
if (saved) return saved === 'dark';
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
});
|
||||||
|
|
||||||
const filteredTopics = useMemo(() => {
|
useEffect(() => {
|
||||||
if (!searchQuery.trim()) return topics;
|
const root = document.documentElement;
|
||||||
|
root.classList.toggle('dark', dark);
|
||||||
|
localStorage.setItem('theme', dark ? 'dark' : 'light');
|
||||||
|
}, [dark]);
|
||||||
|
|
||||||
return topics.map(topic => {
|
const q = searchQuery.trim().toLowerCase();
|
||||||
const matchTopic = topic.name.toLowerCase().includes(searchQuery.toLowerCase());
|
const visibleGraphql = useMemo(() => filterTopics(allGraphql, q), [q]);
|
||||||
const filteredEndpoints = topic.endpoints.filter(ep =>
|
const visibleRest = useMemo(() => filterTopics(allRest, q), [q]);
|
||||||
ep.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
ep.description.toLowerCase().includes(searchQuery.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (matchTopic || filteredEndpoints.length > 0) {
|
// On mobile, picking a topic should close the drawer
|
||||||
return {
|
const selectTopic = (topic) => {
|
||||||
...topic,
|
setActiveTopic(topic);
|
||||||
endpoints: filteredEndpoints.length > 0 ? filteredEndpoints : topic.endpoints
|
setSidebarOpen(false);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}).filter(Boolean);
|
|
||||||
}, [searchQuery]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-50 bg-grid-pattern flex relative overflow-hidden">
|
<div className="min-h-screen bg-slate-50 dark:bg-dark-900 bg-grid-pattern flex relative overflow-hidden transition-colors duration-300">
|
||||||
|
|
||||||
{/* Ambient background glows */}
|
{/* Ambient background glows */}
|
||||||
<div className="absolute top-0 -left-4 w-72 h-72 bg-brand-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob"></div>
|
<div className="absolute top-0 -left-4 w-72 h-72 bg-brand-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 dark:opacity-10 animate-blob"></div>
|
||||||
<div className="absolute top-0 -right-4 w-72 h-72 bg-indigo-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob animation-delay-2000"></div>
|
<div className="absolute top-0 -right-4 w-72 h-72 bg-indigo-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 dark:opacity-10 animate-blob animation-delay-2000"></div>
|
||||||
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob animation-delay-4000"></div>
|
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 dark:opacity-10 animate-blob animation-delay-4000"></div>
|
||||||
|
|
||||||
|
{/* Mobile top bar */}
|
||||||
|
<header className="lg:hidden fixed top-0 left-0 right-0 h-16 z-30 glass flex items-center justify-between px-4">
|
||||||
|
<div className="flex items-center gap-2.5 text-slate-900 dark:text-slate-100 font-bold text-lg">
|
||||||
|
<div className="w-7 h-7 rounded-lg bg-gradient-to-br from-brand-500 to-indigo-600 flex items-center justify-center shadow-glow">
|
||||||
|
<Layers className="text-white w-3.5 h-3.5" />
|
||||||
|
</div>
|
||||||
|
<span className="tracking-tight">NearleDaily</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setSidebarOpen(true)}
|
||||||
|
aria-label="Open navigation menu"
|
||||||
|
className="w-10 h-10 -mr-1 flex items-center justify-center rounded-lg text-slate-600 dark:text-slate-300 hover:bg-slate-100/60 dark:hover:bg-white/5 transition-colors"
|
||||||
|
>
|
||||||
|
<Menu size={22} />
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* Mobile drawer backdrop */}
|
||||||
|
{sidebarOpen && (
|
||||||
|
<div
|
||||||
|
onClick={() => setSidebarOpen(false)}
|
||||||
|
className="lg:hidden fixed inset-0 z-30 bg-slate-900/40 backdrop-blur-sm"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Sidebar */}
|
|
||||||
<Sidebar
|
<Sidebar
|
||||||
topics={filteredTopics}
|
graphqlTopics={visibleGraphql}
|
||||||
|
restTopics={visibleRest}
|
||||||
activeTopic={activeTopic}
|
activeTopic={activeTopic}
|
||||||
setActiveTopic={setActiveTopic}
|
setActiveTopic={selectTopic}
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
setSearchQuery={setSearchQuery}
|
setSearchQuery={setSearchQuery}
|
||||||
|
open={sidebarOpen}
|
||||||
|
onClose={() => setSidebarOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Main Content Area */}
|
<ThemeToggle dark={dark} setDark={setDark} />
|
||||||
<main className="ml-[280px] flex-1 min-h-screen relative z-10">
|
|
||||||
|
<main className="lg:ml-[280px] flex-1 min-h-screen relative z-10 pt-16 lg:pt-0">
|
||||||
{activeTopic ? (
|
{activeTopic ? (
|
||||||
<div className="max-w-[1200px] mx-auto p-12 lg:p-16 opacity-0 animate-fade-in-up">
|
<div className="max-w-[1200px] mx-auto p-5 sm:p-8 lg:p-16 opacity-0 animate-fade-in-up">
|
||||||
<EndpointViewer topic={activeTopic} />
|
<EndpointViewer topic={activeTopic} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="max-w-[1000px] mx-auto px-12 py-20 lg:px-24 lg:py-28 opacity-0 animate-fade-in-up">
|
<div className="opacity-0 animate-fade-in-up">
|
||||||
|
<Introduction
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-50 border border-brand-100 text-brand-600 text-sm font-medium mb-8">
|
allGraphql={allGraphql}
|
||||||
<Zap size={14} className="fill-current" />
|
allRest={allRest}
|
||||||
v2.0 Developer API
|
setActiveTopic={selectTopic}
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
<h1 className="text-4xl lg:text-5xl font-bold text-slate-900 mb-6 tracking-tight">
|
|
||||||
<span className="text-gradient">NearleDaily API</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p className="text-xl text-slate-600 mb-12 max-w-2xl leading-relaxed">
|
|
||||||
A comprehensive, lightning-fast platform designed for logistics, order management, and multi-tenant POS administration.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
{topics.map((topic, index) => {
|
|
||||||
const Icon = topicIcons[topic.id] || Zap;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={topic.id}
|
|
||||||
onClick={() => setActiveTopic(topic)}
|
|
||||||
className="group relative bg-white p-6 rounded-2xl border border-slate-200/60 shadow-sm hover:shadow-xl hover:shadow-brand-500/5 hover:border-brand-200 transition-all duration-300 cursor-pointer overflow-hidden"
|
|
||||||
style={{ animationDelay: `${index * 100}ms` }}
|
|
||||||
>
|
|
||||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-brand-50 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
|
||||||
|
|
||||||
<div className="relative z-10">
|
|
||||||
<h3 className="text-lg font-bold text-slate-900 mb-2 group-hover:text-brand-600 transition-colors flex items-center gap-2">
|
|
||||||
<div className="p-1.5 bg-brand-50 text-brand-600 rounded-md group-hover:bg-brand-100 transition-colors">
|
|
||||||
<Icon size={18} />
|
|
||||||
</div>
|
|
||||||
{topic.name}
|
|
||||||
<ArrowRight size={16} className="opacity-0 -translate-x-4 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 ml-auto" />
|
|
||||||
</h3>
|
|
||||||
<p className="text-sm text-slate-500 leading-relaxed mt-3">
|
|
||||||
{topic.description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-16 flex items-center gap-4 p-6 bg-slate-900 text-slate-300 rounded-2xl shadow-code">
|
|
||||||
<Code2 className="text-brand-400" size={24} />
|
|
||||||
<p className="text-sm">
|
|
||||||
Explore real-time interactive endpoints. All requests are authenticated with secure admin secrets internally for demonstration purposes.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,86 +1,120 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Play, FileJson, Server, CheckCircle2, AlertCircle } from 'lucide-react';
|
import { Play, FileJson, Server, CheckCircle2, AlertCircle, Copy, Check, Loader2 } from 'lucide-react';
|
||||||
import { graphqlMeta } from '../data/apiData';
|
import { graphqlMeta } from '../data/apiData';
|
||||||
|
import { highlightJSON } from '../lib/highlight';
|
||||||
|
|
||||||
|
function safeDecode(v) {
|
||||||
|
try { return decodeURIComponent(v); } catch { return v; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const [, query = ''] = url.split('?');
|
||||||
|
const params = {};
|
||||||
|
if (query) {
|
||||||
|
for (const pair of query.split('&')) {
|
||||||
|
const [name, value = ''] = pair.split('=');
|
||||||
|
if (name) params[name] = safeDecode(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EndpointRow({ endpoint, topic }) {
|
||||||
|
const isRest = topic.type === 'rest';
|
||||||
|
const meta = !isRest ? graphqlMeta[endpoint.name] : null;
|
||||||
|
|
||||||
function EndpointRow({ endpoint }) {
|
|
||||||
const meta = graphqlMeta[endpoint.name];
|
|
||||||
const [queryText, setQueryText] = useState(meta?.query || '');
|
const [queryText, setQueryText] = useState(meta?.query || '');
|
||||||
const [variablesText, setVariablesText] = useState(meta?.variables || '{}');
|
const [variablesText, setVariablesText] = useState(meta?.variables || '{}');
|
||||||
|
const [params, setParams] = useState(() => parseUrlParams(endpoint.url));
|
||||||
const parseParams = (url) => {
|
|
||||||
const parts = url.split('?');
|
|
||||||
if(parts.length < 2) return {};
|
|
||||||
const sp = new URLSearchParams(parts[1]);
|
|
||||||
const obj = {};
|
|
||||||
for(const [k, v] of sp.entries()) obj[k] = v;
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
const [params, setParams] = useState(parseParams(endpoint.url));
|
|
||||||
const [result, setResult] = useState(null);
|
const [result, setResult] = useState(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setQueryText(meta?.query || '');
|
setQueryText(meta?.query || '');
|
||||||
setVariablesText(meta?.variables || '{}');
|
setVariablesText(meta?.variables || '{}');
|
||||||
}, [meta?.query, meta?.variables]);
|
setParams(parseUrlParams(endpoint.url));
|
||||||
|
setResult(null);
|
||||||
useEffect(() => {
|
setError(null);
|
||||||
setParams(parseParams(endpoint.url));
|
|
||||||
}, [endpoint.url]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
try {
|
|
||||||
const parsed = variablesText?.trim() ? JSON.parse(variablesText) : {};
|
|
||||||
if(endpoint.method === 'GET') {
|
|
||||||
const next = {};
|
|
||||||
Object.keys(params).forEach(k => {
|
|
||||||
next[k] = parsed[k] !== undefined ? String(parsed[k]) : params[k];
|
|
||||||
});
|
|
||||||
setParams(next);
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
}, [endpoint.name]);
|
}, [endpoint.name]);
|
||||||
|
|
||||||
|
const copyResponse = async () => {
|
||||||
|
if (!result) return;
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(JSON.stringify(result.data, null, 2));
|
||||||
|
setCopied(true); setTimeout(() => setCopied(false), 1500);
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
const execute = async () => {
|
const execute = async () => {
|
||||||
setError(null);
|
setError(null);
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setResult(null);
|
setResult(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const base = 'https://api.workolik.com';
|
if (isRest) {
|
||||||
let requestUrl = base + endpoint.url;
|
// REST: fetch directly (fiesta.nearle.app supports CORS)
|
||||||
const options = {
|
|
||||||
method: endpoint.method,
|
|
||||||
headers: {
|
|
||||||
'x-hasura-admin-secret': 'nearle-admin-secret',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (endpoint.method === 'GET' && !endpoint.useGraphql) {
|
|
||||||
const emptyKeys = Object.entries(params).filter(([k,v]) => String(v).trim() === '').map(([k])=>k);
|
|
||||||
if (emptyKeys.length) {
|
|
||||||
setError('Required parameter(s): ' + emptyKeys.join(', '));
|
|
||||||
setIsLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const path = endpoint.url.split('?')[0];
|
const path = endpoint.url.split('?')[0];
|
||||||
const qs = new URLSearchParams(params).toString();
|
const isGet = endpoint.method === 'GET';
|
||||||
requestUrl = base + path + (qs ? '?' + qs : '');
|
let url = topic.baseUrl + endpoint.url;
|
||||||
|
|
||||||
|
if (isGet && Object.keys(params).length > 0) {
|
||||||
|
const qs = new URLSearchParams(params).toString();
|
||||||
|
url = topic.baseUrl + path + (qs ? '?' + qs : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: endpoint.method,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isGet && endpoint.body) {
|
||||||
|
options.body = typeof endpoint.body === 'string'
|
||||||
|
? endpoint.body
|
||||||
|
: JSON.stringify(endpoint.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(url, options);
|
||||||
|
const text = await res.text();
|
||||||
|
let data;
|
||||||
|
try { data = JSON.parse(text); } catch { data = text; }
|
||||||
|
setResult({ status: res.status, ok: res.ok, data });
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const parsedVariables = variablesText?.trim() ? JSON.parse(variablesText) : {};
|
// GraphQL / Hasura
|
||||||
requestUrl = base + '/v1/graphql';
|
const base = topic.baseUrl;
|
||||||
options.method = 'POST';
|
let requestUrl = base + endpoint.url;
|
||||||
options.body = JSON.stringify({ query: queryText, variables: parsedVariables });
|
const options = {
|
||||||
|
method: endpoint.method,
|
||||||
|
headers: {
|
||||||
|
'x-hasura-admin-secret': 'nearle-admin-secret',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (endpoint.method === 'GET' && !endpoint.useGraphql) {
|
||||||
|
const emptyKeys = Object.entries(params).filter(([, v]) => String(v).trim() === '').map(([k]) => k);
|
||||||
|
if (emptyKeys.length) {
|
||||||
|
setError('Required parameter(s): ' + emptyKeys.join(', '));
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = endpoint.url.split('?')[0];
|
||||||
|
const qs = new URLSearchParams(params).toString();
|
||||||
|
requestUrl = base + path + (qs ? '?' + qs : '');
|
||||||
|
} else {
|
||||||
|
const parsedVars = variablesText?.trim() ? JSON.parse(variablesText) : {};
|
||||||
|
requestUrl = base + '/v1/graphql';
|
||||||
|
options.method = 'POST';
|
||||||
|
options.body = JSON.stringify({ query: queryText, variables: parsedVars });
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(requestUrl, options);
|
||||||
|
const data = await res.json();
|
||||||
|
setResult({ status: res.status, ok: res.ok, data });
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
const res = await fetch(requestUrl, options);
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
setResult({ status: res.status, ok: res.ok, data });
|
|
||||||
} catch(err) {
|
|
||||||
setError(String(err));
|
setError(String(err));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -88,15 +122,18 @@ function EndpointRow({ endpoint }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const methodColor = {
|
const methodColor = {
|
||||||
GET: 'bg-emerald-100/50 text-emerald-700 border-emerald-200',
|
GET: 'bg-emerald-100/50 text-emerald-700 border-emerald-200',
|
||||||
POST: 'bg-blue-100/50 text-blue-700 border-blue-200',
|
POST: 'bg-blue-100/50 text-blue-700 border-blue-200',
|
||||||
PUT: 'bg-amber-100/50 text-amber-700 border-amber-200',
|
PUT: 'bg-amber-100/50 text-amber-700 border-amber-200',
|
||||||
DELETE: 'bg-red-100/50 text-red-700 border-red-200'
|
DELETE: 'bg-red-100/50 text-red-700 border-red-200',
|
||||||
|
PATCH: 'bg-purple-100/50 text-purple-700 border-purple-200',
|
||||||
}[endpoint.method] || 'bg-slate-100/50 text-slate-700 border-slate-200';
|
}[endpoint.method] || 'bg-slate-100/50 text-slate-700 border-slate-200';
|
||||||
|
|
||||||
|
const urlPath = endpoint.url.split('?')[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-16 border-t border-slate-200/60 group/row" id={endpoint.name}>
|
<div className="py-10 sm:py-16 border-t border-slate-200/60 dark:border-white/10 group/row" id={endpoint.name}>
|
||||||
<div className="grid grid-cols-1 xl:grid-cols-12 gap-12 lg:gap-16">
|
<div className="grid grid-cols-1 xl:grid-cols-12 gap-8 lg:gap-16">
|
||||||
|
|
||||||
{/* Left Column: Description & Parameters */}
|
{/* Left Column: Description & Parameters */}
|
||||||
<div className="xl:col-span-5 space-y-8">
|
<div className="xl:col-span-5 space-y-8">
|
||||||
@@ -105,47 +142,49 @@ function EndpointRow({ endpoint }) {
|
|||||||
<span className={`px-2.5 py-1 rounded text-xs font-bold tracking-widest border ${methodColor}`}>
|
<span className={`px-2.5 py-1 rounded text-xs font-bold tracking-widest border ${methodColor}`}>
|
||||||
{endpoint.method}
|
{endpoint.method}
|
||||||
</span>
|
</span>
|
||||||
<h3 className="text-2xl font-bold text-slate-900 tracking-tight">
|
<h3 className="text-xl sm:text-2xl font-bold text-slate-900 dark:text-slate-100 tracking-tight break-all">
|
||||||
{endpoint.name}
|
{endpoint.name}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[15px] text-slate-600 leading-relaxed">{endpoint.description}</p>
|
<p className="text-[15px] text-slate-600 dark:text-slate-400 leading-relaxed">{endpoint.description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white border border-slate-200/80 rounded-xl p-3.5 font-mono text-sm text-slate-600 break-all shadow-sm flex items-center gap-2 group-hover/row:border-brand-300 transition-colors">
|
<div className="bg-white dark:bg-dark-800 border border-slate-200/80 dark:border-white/10 rounded-xl p-3.5 font-mono text-sm shadow-sm flex items-start gap-2 group-hover/row:border-brand-300 dark:group-hover/row:border-brand-500/40 transition-colors min-w-0">
|
||||||
<Server size={14} className="text-brand-400 shrink-0" />
|
<Server size={14} className="text-brand-400 shrink-0 mt-0.5" />
|
||||||
<span className="opacity-60 hidden sm:inline">https://api.workolik.com</span>
|
<div className="min-w-0 flex-1">
|
||||||
<span className="font-semibold text-slate-800">{endpoint.url.split('?')[0]}</span>
|
<div className="text-xs text-slate-400 dark:text-slate-500 truncate">{topic.baseUrl}</div>
|
||||||
|
<div className="font-semibold text-slate-800 dark:text-slate-200 break-all">{urlPath}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Query params (GET endpoints) */}
|
||||||
{endpoint.method === 'GET' && Object.keys(params).length > 0 && (
|
{endpoint.method === 'GET' && Object.keys(params).length > 0 && (
|
||||||
<div className="pt-2">
|
<div className="pt-2">
|
||||||
<h4 className="text-xs font-bold text-slate-400 mb-4 uppercase tracking-widest flex items-center gap-2">
|
<h4 className="text-xs font-bold text-slate-400 dark:text-slate-500 mb-4 uppercase tracking-widest flex items-center gap-2">
|
||||||
<span className="w-4 h-[1px] bg-slate-300"></span> Query Parameters
|
<span className="w-4 h-[1px] bg-slate-300 dark:bg-slate-600"></span> Query Parameters
|
||||||
</h4>
|
</h4>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{Object.entries(params).map(([key, val]) => (
|
{Object.entries(params).map(([key, val]) => (
|
||||||
<div key={key} className="flex flex-col gap-2">
|
<div key={key} className="flex flex-col gap-2">
|
||||||
<label className="text-sm font-semibold text-slate-800 flex justify-between items-center">
|
<label className="text-sm font-semibold text-slate-800 dark:text-slate-200 flex justify-between items-center">
|
||||||
{key}
|
{key}
|
||||||
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-mono">string</span>
|
<span className="text-[10px] text-slate-400 dark:text-slate-500 uppercase tracking-wider font-mono">string</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 transition-all shadow-sm text-slate-700"
|
className="w-full px-3.5 py-2.5 bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 transition-all shadow-sm text-slate-700 dark:text-slate-200"
|
||||||
value={val}
|
value={val}
|
||||||
placeholder={`Enter ${key}...`}
|
placeholder={`Enter ${key}...`}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
const newVal = e.target.value;
|
const newVal = e.target.value;
|
||||||
setParams(p => {
|
setParams(p => ({ ...p, [key]: newVal }));
|
||||||
const next = {...p, [key]: newVal};
|
if (!isRest) {
|
||||||
try {
|
try {
|
||||||
setVariablesText(JSON.stringify({
|
setVariablesText(JSON.stringify({
|
||||||
...JSON.parse(variablesText || '{}'),
|
...JSON.parse(variablesText || '{}'),
|
||||||
[key]: isNaN(newVal) || newVal === '' ? newVal : Number(newVal)
|
[key]: isNaN(newVal) || newVal === '' ? newVal : Number(newVal)
|
||||||
}, null, 2));
|
}, null, 2));
|
||||||
} catch(err) {}
|
} catch {}
|
||||||
return next;
|
}
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -155,9 +194,9 @@ function EndpointRow({ endpoint }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Column: Execution & Code */}
|
{/* Right Column: Code Panel */}
|
||||||
<div className="xl:col-span-7">
|
<div className="xl:col-span-7">
|
||||||
<div className="dark-glass rounded-2xl overflow-hidden shadow-code flex flex-col h-full min-h-[450px] transform transition-transform duration-500 group-hover/row:-translate-y-1">
|
<div className="dark-glass rounded-2xl overflow-hidden shadow-code flex flex-col h-full min-h-[360px] sm:min-h-[450px] transform transition-transform duration-500 group-hover/row:-translate-y-1">
|
||||||
|
|
||||||
{/* macOS window dots */}
|
{/* macOS window dots */}
|
||||||
<div className="h-10 bg-white/5 border-b border-white/5 flex items-center px-4 gap-2 shrink-0">
|
<div className="h-10 bg-white/5 border-b border-white/5 flex items-center px-4 gap-2 shrink-0">
|
||||||
@@ -167,7 +206,9 @@ function EndpointRow({ endpoint }) {
|
|||||||
<div className="ml-4 text-xs font-mono text-slate-500">Request Payload</div>
|
<div className="ml-4 text-xs font-mono text-slate-500">Request Payload</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Pane content */}
|
||||||
{meta ? (
|
{meta ? (
|
||||||
|
// GraphQL editor: query + variables
|
||||||
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-white/5">
|
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-white/5">
|
||||||
<div className="p-5 flex flex-col group/pane relative">
|
<div className="p-5 flex flex-col group/pane relative">
|
||||||
<div className="text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider flex items-center gap-2">
|
<div className="text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider flex items-center gap-2">
|
||||||
@@ -179,7 +220,6 @@ function EndpointRow({ endpoint }) {
|
|||||||
onChange={e => setQueryText(e.target.value)}
|
onChange={e => setQueryText(e.target.value)}
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-dark-900 via-transparent to-transparent opacity-0 group-hover/pane:opacity-100 pointer-events-none transition-opacity"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="p-5 flex flex-col bg-white/[0.02]">
|
<div className="p-5 flex flex-col bg-white/[0.02]">
|
||||||
<div className="text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider">Variables JSON</div>
|
<div className="text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider">Variables JSON</div>
|
||||||
@@ -191,11 +231,44 @@ function EndpointRow({ endpoint }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : endpoint.body ? (
|
||||||
|
// REST body JSON preview
|
||||||
|
<div className="flex-1 p-5 flex flex-col">
|
||||||
|
<div className="text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider flex items-center gap-2">
|
||||||
|
<FileJson size={14} className="text-brand-400" /> Request Body (JSON)
|
||||||
|
</div>
|
||||||
|
<pre className="flex-1 text-slate-300 font-mono text-[13px] whitespace-pre-wrap leading-relaxed overflow-auto scrollbar-hide"
|
||||||
|
dangerouslySetInnerHTML={{ __html: highlightJSON(endpoint.body) }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 p-8 flex items-center justify-center">
|
// URL preview for no-body endpoints
|
||||||
<div className="text-center">
|
<div className="flex-1 p-8 flex flex-col justify-start">
|
||||||
<FileJson size={32} className="mx-auto text-slate-700 mb-4" />
|
<div className="text-[11px] font-bold text-slate-400 mb-4 uppercase tracking-wider flex items-center gap-2">
|
||||||
<p className="text-slate-500 text-sm">No specific payload configuration required.</p>
|
<Server size={14} className="text-brand-400" /> Full Request URL
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-[13px] leading-loose break-all">
|
||||||
|
<span className={`font-bold mr-2 ${
|
||||||
|
endpoint.method === 'GET' ? 'text-emerald-400' :
|
||||||
|
endpoint.method === 'POST' ? 'text-blue-400' :
|
||||||
|
endpoint.method === 'PUT' ? 'text-amber-400' :
|
||||||
|
endpoint.method === 'DELETE' ? 'text-red-400' : 'text-purple-400'
|
||||||
|
}`}>{endpoint.method}</span>
|
||||||
|
<span className="text-slate-500">{topic.baseUrl}</span>
|
||||||
|
<span className="text-slate-200">{urlPath}</span>
|
||||||
|
{Object.keys(params).length > 0 && (
|
||||||
|
<>
|
||||||
|
<span className="text-pink-400">?</span>
|
||||||
|
{Object.entries(params).map(([k, v], i, arr) => (
|
||||||
|
<span key={k}>
|
||||||
|
<span className="text-brand-300">{k}</span>
|
||||||
|
<span className="text-slate-500">=</span>
|
||||||
|
<span className="text-slate-300">{encodeURIComponent(v)}</span>
|
||||||
|
{i < arr.length - 1 && <span className="text-slate-600">&</span>}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -210,11 +283,9 @@ function EndpointRow({ endpoint }) {
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="bg-brand-600 hover:bg-brand-500 text-white px-5 py-2 rounded-lg text-sm font-semibold transition-all flex items-center gap-2 disabled:opacity-50 shadow-[0_0_15px_rgba(2,132,199,0.4)] hover:shadow-[0_0_25px_rgba(2,132,199,0.6)] hover:-translate-y-0.5 active:translate-y-0"
|
className="bg-brand-600 hover:bg-brand-500 text-white px-5 py-2 rounded-lg text-sm font-semibold transition-all flex items-center gap-2 disabled:opacity-50 shadow-[0_0_15px_rgba(2,132,199,0.4)] hover:shadow-[0_0_25px_rgba(2,132,199,0.6)] hover:-translate-y-0.5 active:translate-y-0"
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading
|
||||||
<div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
? <div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||||
) : (
|
: <Play size={14} className="fill-current" />}
|
||||||
<Play size={14} className="fill-current" />
|
|
||||||
)}
|
|
||||||
{isLoading ? 'Executing...' : 'Send Request'}
|
{isLoading ? 'Executing...' : 'Send Request'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -224,19 +295,33 @@ function EndpointRow({ endpoint }) {
|
|||||||
<div className="border-t border-white/10 p-5 max-h-[350px] overflow-y-auto bg-black/60 relative">
|
<div className="border-t border-white/10 p-5 max-h-[350px] overflow-y-auto bg-black/60 relative">
|
||||||
<div className="sticky top-0 pb-3 mb-3 bg-black/60 backdrop-blur-md border-b border-white/5 flex items-center justify-between">
|
<div className="sticky top-0 pb-3 mb-3 bg-black/60 backdrop-blur-md border-b border-white/5 flex items-center justify-between">
|
||||||
<span className="text-[11px] font-bold text-slate-400 uppercase tracking-wider">Response JSON</span>
|
<span className="text-[11px] font-bold text-slate-400 uppercase tracking-wider">Response JSON</span>
|
||||||
{result && (
|
<div className="flex items-center gap-3">
|
||||||
<span className={`text-[11px] px-2.5 py-1 rounded-md font-bold font-mono flex items-center gap-1.5 ${result.ok ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-red-500/20 text-red-400 border border-red-500/30'}`}>
|
{result && (
|
||||||
{result.ok ? <CheckCircle2 size={12} /> : <AlertCircle size={12} />}
|
<>
|
||||||
{result.status}
|
<span className={`text-[11px] px-2.5 py-1 rounded-md font-bold font-mono flex items-center gap-1.5 ${result.ok ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-red-500/20 text-red-400 border border-red-500/30'}`}>
|
||||||
</span>
|
{result.ok ? <CheckCircle2 size={12} /> : <AlertCircle size={12} />}
|
||||||
)}
|
{result.status}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={copyResponse}
|
||||||
|
className="flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-widest text-slate-400 hover:text-brand-400 transition-colors"
|
||||||
|
>
|
||||||
|
{copied ? <Check size={12} /> : <Copy size={12} />}
|
||||||
|
{copied ? 'Copied' : 'Copy'}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="text-red-400 font-mono text-[13px] leading-relaxed break-all">{error}</div>
|
<div className="text-red-400 font-mono text-[13px] leading-relaxed break-all">{error}</div>
|
||||||
|
) : typeof result?.data === 'string' ? (
|
||||||
|
<pre className="text-slate-300 font-mono text-[13px] whitespace-pre-wrap leading-relaxed">{result.data}</pre>
|
||||||
) : (
|
) : (
|
||||||
<pre className="text-slate-300 font-mono text-[13px] whitespace-pre-wrap leading-relaxed">
|
<pre
|
||||||
{JSON.stringify(result.data, null, 2)}
|
className="text-slate-300 font-mono text-[13px] whitespace-pre-wrap leading-relaxed"
|
||||||
</pre>
|
dangerouslySetInnerHTML={{ __html: highlightJSON(result?.data) }}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -254,13 +339,24 @@ export default function EndpointViewer({ topic }) {
|
|||||||
return (
|
return (
|
||||||
<div className="pb-24">
|
<div className="pb-24">
|
||||||
<div className="mb-12">
|
<div className="mb-12">
|
||||||
<h1 className="text-4xl lg:text-5xl font-bold text-slate-900 mb-4 tracking-tight">{topic.name}</h1>
|
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-slate-900 dark:text-slate-100 mb-4 tracking-tight break-words">{topic.name}</h1>
|
||||||
<p className="text-lg text-slate-600 max-w-3xl leading-relaxed">{topic.description}</p>
|
<p className="text-base sm:text-lg text-slate-600 dark:text-slate-400 max-w-3xl leading-relaxed">{topic.description}</p>
|
||||||
|
<div className="mt-4 flex items-center gap-3">
|
||||||
|
<span className={`inline-flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-widest px-3 py-1 rounded-full border ${
|
||||||
|
topic.type === 'graphql'
|
||||||
|
? 'bg-brand-50 dark:bg-brand-500/10 text-brand-600 dark:text-brand-400 border-brand-100 dark:border-brand-500/20'
|
||||||
|
: 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-100 dark:border-indigo-500/20'
|
||||||
|
}`}>
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-current"></span>
|
||||||
|
{topic.type === 'graphql' ? 'GraphQL' : 'REST API'}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-slate-400 dark:text-slate-500">{topic.endpoints.length} endpoint{topic.endpoints.length !== 1 ? 's' : ''}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{topic.endpoints.map(endpoint => (
|
{topic.endpoints.map(endpoint => (
|
||||||
<EndpointRow key={endpoint.name} endpoint={endpoint} />
|
<EndpointRow key={`${topic.uniqueId}/${endpoint.name}`} endpoint={endpoint} topic={topic} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
103
src/components/Introduction.jsx
Normal file
103
src/components/Introduction.jsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ArrowRight, Code2, Zap, Users, ShoppingCart, Home, Box, Link2, Truck, UserCircle, Bike, FileText, CreditCard, Wrench } from 'lucide-react';
|
||||||
|
import { GRAPHQL_BASE_URL } from '../data/apiData';
|
||||||
|
import { REST_BASE_URL } from '../data/restTopics';
|
||||||
|
|
||||||
|
const topicIcons = {
|
||||||
|
users: Users,
|
||||||
|
orders: ShoppingCart,
|
||||||
|
tenants: Home,
|
||||||
|
products: Box,
|
||||||
|
locations: Link2,
|
||||||
|
partners: Bike,
|
||||||
|
deliveries: Truck,
|
||||||
|
customers: UserCircle,
|
||||||
|
invoice: FileText,
|
||||||
|
payments: CreditCard,
|
||||||
|
utils: Wrench,
|
||||||
|
mobile: Box,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Introduction({ allGraphql, allRest, setActiveTopic }) {
|
||||||
|
const allTopics = [...allGraphql, ...allRest];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-[1000px] mx-auto px-5 py-12 sm:px-12 sm:py-20 lg:px-24 lg:py-28">
|
||||||
|
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-50 dark:bg-brand-500/10 border border-brand-100 dark:border-brand-500/20 text-brand-600 dark:text-brand-400 text-sm font-medium mb-8">
|
||||||
|
<Zap size={14} className="fill-current" />
|
||||||
|
v2.0 Developer API
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-slate-900 dark:text-slate-100 mb-6 tracking-tight">
|
||||||
|
<span className="text-gradient">NearleDaily API</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-lg sm:text-xl text-slate-600 dark:text-slate-400 mb-12 max-w-2xl leading-relaxed">
|
||||||
|
A comprehensive, lightning-fast platform designed for logistics, order management,
|
||||||
|
and multi-tenant POS administration — available through both Hasura GraphQL and REST APIs.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mb-8">
|
||||||
|
<h2 className="text-xs font-bold uppercase tracking-widest text-slate-400 dark:text-slate-500 mb-4">Base URLs</h2>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-10">
|
||||||
|
<div className="bg-white dark:bg-dark-800 border border-slate-200/60 dark:border-white/10 rounded-xl p-4 shadow-sm">
|
||||||
|
<div className="text-[11px] text-brand-600 dark:text-brand-400 font-bold uppercase tracking-widest mb-1.5">GraphQL</div>
|
||||||
|
<code className="font-mono text-sm text-slate-700 dark:text-slate-300 break-all">{GRAPHQL_BASE_URL}</code>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white dark:bg-dark-800 border border-slate-200/60 dark:border-white/10 rounded-xl p-4 shadow-sm">
|
||||||
|
<div className="text-[11px] text-indigo-600 dark:text-indigo-400 font-bold uppercase tracking-widest mb-1.5">REST API</div>
|
||||||
|
<code className="font-mono text-sm text-slate-700 dark:text-slate-300 break-all">{REST_BASE_URL}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
{allTopics.map((topic, index) => {
|
||||||
|
const Icon = topicIcons[topic.id] || Zap;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={topic.uniqueId}
|
||||||
|
onClick={() => setActiveTopic(topic)}
|
||||||
|
className="group relative bg-white dark:bg-dark-800 p-6 rounded-2xl border border-slate-200/60 dark:border-white/10 shadow-sm hover:shadow-xl hover:shadow-brand-500/5 hover:border-brand-200 dark:hover:border-brand-500/30 transition-all duration-300 cursor-pointer overflow-hidden"
|
||||||
|
style={{ animationDelay: `${index * 80}ms` }}
|
||||||
|
>
|
||||||
|
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-brand-50 dark:from-brand-500/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
||||||
|
|
||||||
|
<div className="relative z-10">
|
||||||
|
<h3 className="text-lg font-bold text-slate-900 dark:text-slate-100 mb-2 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors flex items-center gap-2">
|
||||||
|
<div className="p-1.5 bg-brand-50 dark:bg-brand-500/10 text-brand-600 dark:text-brand-400 rounded-md group-hover:bg-brand-100 dark:group-hover:bg-brand-500/20 transition-colors">
|
||||||
|
<Icon size={18} />
|
||||||
|
</div>
|
||||||
|
{topic.name}
|
||||||
|
<ArrowRight size={16} className="opacity-0 -translate-x-4 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 ml-auto" />
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-2 mt-1 mb-2">
|
||||||
|
<span className={`text-[10px] font-bold uppercase tracking-widest px-2 py-0.5 rounded border ${
|
||||||
|
topic.type === 'graphql'
|
||||||
|
? 'bg-brand-50 dark:bg-brand-500/10 text-brand-600 dark:text-brand-400 border-brand-100 dark:border-brand-500/20'
|
||||||
|
: 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-100 dark:border-indigo-500/20'
|
||||||
|
}`}>
|
||||||
|
{topic.type === 'graphql' ? 'GraphQL' : 'REST'}
|
||||||
|
</span>
|
||||||
|
<span className="text-[11px] text-slate-400 dark:text-slate-500">{topic.endpoints.length} endpoint{topic.endpoints.length !== 1 ? 's' : ''}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-slate-500 dark:text-slate-400 leading-relaxed">
|
||||||
|
{topic.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-16 flex items-center gap-4 p-6 bg-slate-900 dark:bg-dark-700 text-slate-300 rounded-2xl shadow-code border border-transparent dark:border-white/5">
|
||||||
|
<Code2 className="text-brand-400 shrink-0" size={24} />
|
||||||
|
<p className="text-sm">
|
||||||
|
Explore real-time interactive endpoints. GraphQL requests are authenticated with the admin secret. REST endpoints support CORS and can be called directly from the browser.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,36 +1,83 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Search, ChevronRight, ChevronDown, Layers, Terminal, Users, ShoppingCart, Home, Box, Link2 } from 'lucide-react';
|
import { Search, ChevronRight, ChevronDown, Layers, Terminal, Users, ShoppingCart, Home, Box, Link2, Truck, UserCircle, Bike, FileText, CreditCard, Wrench, X } from 'lucide-react';
|
||||||
|
|
||||||
const topicIcons = {
|
const topicIcons = {
|
||||||
users: Users,
|
users: Users,
|
||||||
orders: ShoppingCart,
|
orders: ShoppingCart,
|
||||||
tenants: Home,
|
tenants: Home,
|
||||||
products: Box,
|
products: Box,
|
||||||
locations: Link2,
|
locations: Link2,
|
||||||
partners: Users,
|
partners: Bike,
|
||||||
|
deliveries: Truck,
|
||||||
|
customers: UserCircle,
|
||||||
|
invoice: FileText,
|
||||||
|
payments: CreditCard,
|
||||||
|
utils: Wrench,
|
||||||
|
mobile: Box,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Sidebar({ topics, activeTopic, setActiveTopic, searchQuery, setSearchQuery }) {
|
export default function Sidebar({ graphqlTopics, restTopics, activeTopic, setActiveTopic, searchQuery, setSearchQuery, open: drawerOpen = false, onClose }) {
|
||||||
const [expanded, setExpanded] = useState({ general: true, topics: true });
|
const [open, setOpen] = useState({ general: true, graphql: true, rest: true });
|
||||||
|
const toggle = (key) => setOpen(prev => ({ ...prev, [key]: !prev[key] }));
|
||||||
|
|
||||||
const toggle = (key) => setExpanded(prev => ({ ...prev, [key]: !prev[key] }));
|
const renderGroup = (topics, title, key) => (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() => toggle(key)}
|
||||||
|
className="w-full flex items-center justify-between px-2 py-1.5 text-slate-800 dark:text-slate-200 font-semibold text-sm hover:text-brand-600 dark:hover:text-brand-400 transition-colors group"
|
||||||
|
>
|
||||||
|
<span className="tracking-wide text-xs uppercase text-slate-400 dark:text-slate-500 group-hover:text-brand-500 transition-colors">{title}</span>
|
||||||
|
{open[key] ? <ChevronDown size={14} className="text-slate-400 dark:text-slate-500" /> : <ChevronRight size={14} className="text-slate-400 dark:text-slate-500" />}
|
||||||
|
</button>
|
||||||
|
<div className={`mt-2 space-y-1 overflow-hidden transition-all duration-500 ${open[key] ? 'max-h-[800px] opacity-100' : 'max-h-0 opacity-0'}`}>
|
||||||
|
{topics.map(topic => {
|
||||||
|
const isActive = activeTopic?.uniqueId === topic.uniqueId;
|
||||||
|
const Icon = topicIcons[topic.id] || Layers;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={topic.uniqueId}
|
||||||
|
onClick={() => setActiveTopic(topic)}
|
||||||
|
className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 group ${
|
||||||
|
isActive
|
||||||
|
? 'text-brand-700 dark:text-brand-300 bg-brand-50 dark:bg-brand-500/10 shadow-sm font-medium'
|
||||||
|
: 'text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 hover:bg-slate-100/50 dark:hover:bg-white/5'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Icon size={16} className={`${isActive ? 'text-brand-500' : 'text-slate-400 dark:text-slate-500 group-hover:text-slate-500 dark:group-hover:text-slate-400'} transition-colors`} />
|
||||||
|
{topic.name}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-[280px] glass h-screen fixed top-0 left-0 flex flex-col z-20 transition-all">
|
<div className={`w-[280px] glass h-screen fixed top-0 left-0 flex flex-col z-40 transition-transform duration-300 lg:translate-x-0 ${drawerOpen ? 'translate-x-0' : '-translate-x-full'}`}>
|
||||||
|
|
||||||
{/* Brand Header */}
|
{/* Brand Header */}
|
||||||
<div className="p-6 border-b border-slate-100/50">
|
<div className="p-6 border-b border-slate-100/50 dark:border-white/5">
|
||||||
<div className="flex items-center gap-3 text-slate-900 font-bold text-xl mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-brand-500 to-indigo-600 flex items-center justify-center shadow-glow">
|
<div className="flex items-center gap-3 text-slate-900 dark:text-slate-100 font-bold text-xl">
|
||||||
<Layers className="text-white w-4 h-4" />
|
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-brand-500 to-indigo-600 flex items-center justify-center shadow-glow">
|
||||||
|
<Layers className="text-white w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
<span className="tracking-tight">NearleDaily</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="tracking-tight">NearleDaily</span>
|
{/* Close button (mobile drawer only) */}
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
aria-label="Close navigation menu"
|
||||||
|
className="lg:hidden w-8 h-8 -mr-1 flex items-center justify-center rounded-lg text-slate-500 dark:text-slate-400 hover:bg-slate-100/60 dark:hover:bg-white/5 transition-colors"
|
||||||
|
>
|
||||||
|
<X size={18} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
<Search className="w-4 h-4 absolute left-3 top-3 text-slate-400 group-focus-within:text-brand-500 transition-colors" />
|
<Search className="w-4 h-4 absolute left-3 top-3 text-slate-400 group-focus-within:text-brand-500 transition-colors" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="w-full pl-9 pr-3 py-2.5 bg-slate-50/50 border border-slate-200/60 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 focus:bg-white transition-all placeholder:text-slate-400"
|
className="w-full pl-9 pr-3 py-2.5 bg-slate-50/50 dark:bg-white/5 border border-slate-200/60 dark:border-white/10 rounded-xl text-sm text-slate-700 dark:text-slate-200 focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 focus:bg-white dark:focus:bg-white/10 transition-all placeholder:text-slate-400 dark:placeholder:text-slate-500"
|
||||||
placeholder="Search documentation..."
|
placeholder="Search documentation..."
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
@@ -41,60 +88,32 @@ export default function Sidebar({ topics, activeTopic, setActiveTopic, searchQue
|
|||||||
<div className="flex-1 overflow-y-auto py-6 px-4 scrollbar-hide">
|
<div className="flex-1 overflow-y-auto py-6 px-4 scrollbar-hide">
|
||||||
<nav className="space-y-6">
|
<nav className="space-y-6">
|
||||||
|
|
||||||
{/* General Section */}
|
{/* Getting Started */}
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
onClick={() => toggle('general')}
|
onClick={() => toggle('general')}
|
||||||
className="w-full flex items-center justify-between px-2 py-1.5 text-slate-800 font-semibold text-sm hover:text-brand-600 transition-colors group"
|
className="w-full flex items-center justify-between px-2 py-1.5 text-slate-800 dark:text-slate-200 font-semibold text-sm hover:text-brand-600 dark:hover:text-brand-400 transition-colors group"
|
||||||
>
|
>
|
||||||
<span className="tracking-wide text-xs uppercase text-slate-400 group-hover:text-brand-500 transition-colors">Getting Started</span>
|
<span className="tracking-wide text-xs uppercase text-slate-400 dark:text-slate-500 group-hover:text-brand-500 transition-colors">Getting Started</span>
|
||||||
{expanded.general ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
{open.general ? <ChevronDown size={14} className="text-slate-400 dark:text-slate-500" /> : <ChevronRight size={14} className="text-slate-400 dark:text-slate-500" />}
|
||||||
</button>
|
</button>
|
||||||
<div className={`mt-2 space-y-1 overflow-hidden transition-all duration-300 ${expanded.general ? 'max-h-40 opacity-100' : 'max-h-0 opacity-0'}`}>
|
<div className={`mt-2 space-y-1 overflow-hidden transition-all duration-300 ${open.general ? 'max-h-40 opacity-100' : 'max-h-0 opacity-0'}`}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTopic(null)}
|
onClick={() => setActiveTopic(null)}
|
||||||
className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 ${
|
className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 ${
|
||||||
!activeTopic
|
!activeTopic
|
||||||
? 'text-brand-700 bg-brand-50 shadow-sm font-medium'
|
? 'text-brand-700 dark:text-brand-300 bg-brand-50 dark:bg-brand-500/10 shadow-sm font-medium'
|
||||||
: 'text-slate-600 hover:text-slate-900 hover:bg-slate-100/50'
|
: 'text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 hover:bg-slate-100/50 dark:hover:bg-white/5'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Terminal size={16} className={!activeTopic ? "text-brand-500" : "text-slate-400"} />
|
<Terminal size={16} className={!activeTopic ? 'text-brand-500' : 'text-slate-400 dark:text-slate-500'} />
|
||||||
Introduction
|
Introduction
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Topics Section */}
|
{graphqlTopics.length > 0 && renderGroup(graphqlTopics, 'GraphQL', 'graphql')}
|
||||||
<div>
|
{restTopics.length > 0 && renderGroup(restTopics, 'REST API', 'rest')}
|
||||||
<button
|
|
||||||
onClick={() => toggle('topics')}
|
|
||||||
className="w-full flex items-center justify-between px-2 py-1.5 text-slate-800 font-semibold text-sm hover:text-brand-600 transition-colors group"
|
|
||||||
>
|
|
||||||
<span className="tracking-wide text-xs uppercase text-slate-400 group-hover:text-brand-500 transition-colors">API Reference</span>
|
|
||||||
{expanded.topics ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
|
||||||
</button>
|
|
||||||
<div className={`mt-2 space-y-1 overflow-hidden transition-all duration-500 ${expanded.topics ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0'}`}>
|
|
||||||
{topics.map(topic => {
|
|
||||||
const isActive = activeTopic?.id === topic.id;
|
|
||||||
const Icon = topicIcons[topic.id] || Layers;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={topic.id}
|
|
||||||
onClick={() => setActiveTopic(topic)}
|
|
||||||
className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 group ${
|
|
||||||
isActive
|
|
||||||
? 'text-brand-700 bg-brand-50 shadow-sm font-medium'
|
|
||||||
: 'text-slate-600 hover:text-slate-900 hover:bg-slate-100/50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Icon size={16} className={`${isActive ? "text-brand-500" : "text-slate-400 group-hover:text-slate-500"} transition-colors`} />
|
|
||||||
{topic.name}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
21
src/components/ThemeToggle.jsx
Normal file
21
src/components/ThemeToggle.jsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Sun, Moon } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function ThemeToggle({ dark, setDark }) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={() => setDark(d => !d)}
|
||||||
|
aria-label={dark ? 'Switch to light theme' : 'Switch to dark theme'}
|
||||||
|
title={dark ? 'Light mode' : 'Dark mode'}
|
||||||
|
className="fixed top-3.5 right-16 lg:top-4 lg:right-4 z-50 w-11 h-11 rounded-full flex items-center justify-center
|
||||||
|
glass shadow-glass border border-slate-200/60 dark:border-white/10
|
||||||
|
text-slate-600 dark:text-slate-300 hover:text-brand-500 dark:hover:text-brand-400
|
||||||
|
hover:shadow-glow hover:-translate-y-0.5 active:translate-y-0
|
||||||
|
transition-all duration-300"
|
||||||
|
>
|
||||||
|
{dark
|
||||||
|
? <Sun size={18} className="transition-transform duration-300" />
|
||||||
|
: <Moon size={18} className="transition-transform duration-300" />}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -206,11 +206,27 @@ export const graphqlMeta = {
|
|||||||
},
|
},
|
||||||
getlocationsconfig: {
|
getlocationsconfig: {
|
||||||
query: /* GraphQL */ /* GraphQL */ `
|
query: /* GraphQL */ /* GraphQL */ `
|
||||||
query GetLocationsConfig {
|
query GetLocations {
|
||||||
app_location_config {
|
details: app_location(where: {status: {_eq: "Active"}}) {
|
||||||
configid
|
applocationid
|
||||||
configvalue
|
locationname
|
||||||
locationid
|
image
|
||||||
|
city
|
||||||
|
state
|
||||||
|
postcode
|
||||||
|
latitude
|
||||||
|
longitude
|
||||||
|
opentime
|
||||||
|
closetime
|
||||||
|
radius
|
||||||
|
applocationadmins: app_locationconfigs(where: {notify: {_eq: "true"}}) {
|
||||||
|
applocationid
|
||||||
|
userid
|
||||||
|
notify
|
||||||
|
app_user {
|
||||||
|
userfcmtokem: userfcmtoken
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -664,9 +680,171 @@ export const graphqlMeta = {
|
|||||||
"billstatus": 1
|
"billstatus": 1
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
|
getcustomerlocations: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetCustomerLocations($customerid: bigint!) {
|
||||||
|
customer_locations(where: { customerid: { _eq: $customerid } }) {
|
||||||
|
locationid
|
||||||
|
latitude
|
||||||
|
longitude
|
||||||
|
address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "customerid": 6060\n}`,
|
||||||
|
},
|
||||||
|
getcustomerordersv3: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetCustomerOrders($customerid: bigint!, $tenantid: bigint!, $moduleid: bigint!, $fromdate: timestamptz!, $todate: timestamptz!, $orderstatus: String!, $keyword: String, $limit: Int!, $offset: Int!) {
|
||||||
|
orders(
|
||||||
|
where: {
|
||||||
|
customerid: { _eq: $customerid }
|
||||||
|
tenantid: { _eq: $tenantid }
|
||||||
|
moduleid: { _eq: $moduleid }
|
||||||
|
orderstatus: { _eq: $orderstatus }
|
||||||
|
orderdate: { _gte: $fromdate, _lte: $todate }
|
||||||
|
_or: [{ orderid: { _ilike: $keyword } }]
|
||||||
|
}
|
||||||
|
limit: $limit
|
||||||
|
offset: $offset
|
||||||
|
) {
|
||||||
|
orderid
|
||||||
|
orderstatus
|
||||||
|
orderamount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "customerid": 6060,\n "tenantid": 1087,\n "moduleid": 2,\n "fromdate": "2026-01-01T00:00:00",\n "todate": "2026-12-31T23:59:59",\n "orderstatus": "delivered",\n "keyword": "%pizza%",\n "limit": 10,\n "offset": 0\n}`,
|
||||||
|
},
|
||||||
|
getcustomer: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetCustomer($customerid: bigint!) {
|
||||||
|
customers(where: { customerid: { _eq: $customerid } }) {
|
||||||
|
customerid
|
||||||
|
name
|
||||||
|
contactno
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "customerid": 6060\n}`,
|
||||||
|
},
|
||||||
|
getcustomerrequests: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetCustomerRequests($customerid: bigint!, $limit: Int!, $offset: Int!) {
|
||||||
|
customer_requests(where: { customerid: { _eq: $customerid } }, limit: $limit, offset: $offset) {
|
||||||
|
requestid
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "customerid": 6060,\n "limit": 10,\n "offset": 0\n}`,
|
||||||
|
},
|
||||||
|
getmobileproductsubcategories: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetProductSubcategories($categoryid: bigint!) {
|
||||||
|
app_subcategory(where: { categoryid: { _eq: $categoryid } }) {
|
||||||
|
subcategoryid
|
||||||
|
subcategoryname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "categoryid": 1001\n}`,
|
||||||
|
},
|
||||||
|
getmobileappcategories: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetAppCategories {
|
||||||
|
app_category {
|
||||||
|
categoryid
|
||||||
|
categoryname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{}`,
|
||||||
|
},
|
||||||
|
getmobileproductvariants: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetProductVariants($tenantid: bigint!, $subcategoryid: bigint!) {
|
||||||
|
product_variants(where: { tenantid: { _eq: $tenantid }, subcategoryid: { _eq: $subcategoryid } }) {
|
||||||
|
variantid
|
||||||
|
productname
|
||||||
|
price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "tenantid": 1087,\n "subcategoryid": 14\n}`,
|
||||||
|
},
|
||||||
|
gettenantpromotions: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetTenantPromotions($tenantid: bigint!, $locationid: bigint!) {
|
||||||
|
promotions(where: { tenantid: { _eq: $tenantid }, locationid: { _eq: $locationid } }) {
|
||||||
|
promotionid
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "tenantid": 1087,\n "locationid": 1\n}`,
|
||||||
|
},
|
||||||
|
getappconfig: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetAppConfig($configid: bigint!) {
|
||||||
|
app_config(where: { configid: { _eq: $configid } }) {
|
||||||
|
configkey
|
||||||
|
configvalue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "configid": 15\n}`,
|
||||||
|
},
|
||||||
|
searchcustomers: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query SearchCustomers($tenantid: bigint!, $keyword: String!) {
|
||||||
|
customers(where: { tenantid: { _eq: $tenantid }, name: { _ilike: $keyword } }) {
|
||||||
|
customerid
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "tenantid": 1087,\n "keyword": "%john%"\n}`,
|
||||||
|
},
|
||||||
|
gettenantorders: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetTenantOrders {
|
||||||
|
orders {
|
||||||
|
orderid
|
||||||
|
tenantid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{}`,
|
||||||
|
},
|
||||||
|
getstaff: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetStaff($tenantid: bigint!) {
|
||||||
|
staff(where: { tenantid: { _eq: $tenantid } }) {
|
||||||
|
staffid
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{\n "tenantid": 1087\n}`,
|
||||||
|
},
|
||||||
|
getmobileapplocations: {
|
||||||
|
query: /* GraphQL */ `
|
||||||
|
query GetAppLocations {
|
||||||
|
app_location {
|
||||||
|
applocationid
|
||||||
|
locationname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: `{}`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const topics = [
|
|
||||||
|
export const GRAPHQL_BASE_URL = 'https://api.workolik.com';
|
||||||
|
|
||||||
|
export const graphqlTopics = [
|
||||||
{
|
{
|
||||||
id: "users",
|
id: "users",
|
||||||
name: "Users",
|
name: "Users",
|
||||||
@@ -875,4 +1053,125 @@ export const topics = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "mobile",
|
||||||
|
name: "Mobile",
|
||||||
|
description:
|
||||||
|
"Specific endpoints and GraphQL queries optimized for mobile application integration.",
|
||||||
|
endpoints: [
|
||||||
|
{
|
||||||
|
name: "getcustomerlocations",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getcustomerlocations?customerid=6060",
|
||||||
|
description:
|
||||||
|
"Retrieve physical locations associated with a specific customer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getcustomerordersv3",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getcustomerordersv3?customerid=6060&tenantid=1087&moduleid=2&fromdate=2026-01-01T00:00:00&todate=2026-12-31T23:59:59&orderstatus=delivered&keyword=%25pizza%25&limit=10&offset=0",
|
||||||
|
description:
|
||||||
|
"Fetch comprehensive order history for a customer with advanced filtering.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getcustomer",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getcustomer?customerid=6060",
|
||||||
|
description: "Get profile details for a specific customer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getcustomerrequests",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getcustomerrequests?customerid=6060&limit=10&offset=0",
|
||||||
|
description: "List all service requests made by a customer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getmobileproductsubcategories",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getmobileproductsubcategories?categoryid=1001",
|
||||||
|
description:
|
||||||
|
"Retrieve subcategories under a specific product category for mobile display.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getmobileappcategories",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getmobileappcategories",
|
||||||
|
description: "Fetch all available application categories.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getmobileproductvariants",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getmobileproductvariants?tenantid=1087&subcategoryid=14",
|
||||||
|
description: "Get product variants filtered by tenant and subcategory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gettenantpromotions",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/gettenantpromotions?tenantid=1087&locationid=1",
|
||||||
|
description: "Retrieve active promotions for a specific tenant location.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getappconfig",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getappconfig?configid=15",
|
||||||
|
description: "Retrieve specific application configuration settings.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "searchcustomers",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/searchcustomers?tenantid=1087&keyword=%25john%25",
|
||||||
|
description: "Search for customers by name within a tenant's scope.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gettenantorders",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/gettenantorders",
|
||||||
|
description: "List orders across tenants (Admin level).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getstaff",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getstaff?tenantid=1087",
|
||||||
|
description: "Retrieve staff members associated with a specific tenant.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gettenantinfo",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/gettenantinfo?tenantid=1079",
|
||||||
|
description: "Get basic information about a tenant.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gettenantlocations",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/gettenantlocations?tenantid=1",
|
||||||
|
description: "Fetch all locations for a given tenant.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getmobileapplocations",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getmobileapplocations",
|
||||||
|
description: "Retrieve all application-wide locations.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getsubcategory",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getsubcategory?moduleid=6&categoryid=1",
|
||||||
|
description: "Get detailed subcategory info.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getpartners",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getpartners?applocationid=1&partnerid=44&limit=10&offset=0",
|
||||||
|
description: "Retrieve partner details for mobile integration.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getlocationsconfig",
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/rest/getlocationsconfig",
|
||||||
|
useGraphql: true,
|
||||||
|
description: "Get location configuration settings.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
177
src/data/restTopics.js
Normal file
177
src/data/restTopics.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
export const REST_BASE_URL = 'https://fiesta.nearle.app';
|
||||||
|
|
||||||
|
export const restTopics = [
|
||||||
|
{
|
||||||
|
"id": "utils",
|
||||||
|
"name": "Utils",
|
||||||
|
"description": "Shared lookup endpoints: app categories, subcategories, locations, app types, configs.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Fetch application categories by tag (Web)", "method": "GET", "url": "/live/api/v1/web/utils/getapptypes?tag=customer", "description": "Fetch application categories by tag (Web)" },
|
||||||
|
{ "name": "Resolve subcategories (Web)", "method": "GET", "url": "/live/api/v1/web/utils/getsubcategories?moduleid=1&categoryid=2", "description": "Resolve subcategories (Web)" },
|
||||||
|
{ "name": "Fetch system active geofence details (Web)", "method": "GET", "url": "/live/api/v1/web/utils/getapplocations?applocationid=1", "description": "Fetch system active geofence details (Web)" },
|
||||||
|
{ "name": "Fetch global system categories configurations (Web)", "method": "GET", "url": "/live/api/v1/web/utils/getappcategories", "description": "Fetch global system categories configurations (Web)" },
|
||||||
|
{ "name": "Get mobile geofence configuration details (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getapplocationconfig?applocationid=1", "description": "Get mobile geofence configuration details (Mobile)" },
|
||||||
|
{ "name": "Get mobile active geofence details (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getapplocations?applocationid=1", "description": "Get mobile active geofence details (Mobile)" },
|
||||||
|
{ "name": "Fetch mobile app types by tag (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getapptypes?tag=rider", "description": "Fetch mobile app types by tag (Mobile)" },
|
||||||
|
{ "name": "Fetch global payment & geofence configs (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getappconfig?configid=1", "description": "Fetch global payment & geofence configs (Mobile)" },
|
||||||
|
{ "name": "Get mobile category subcategories list (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getsubcategories?moduleid=1&categoryid=2", "description": "Get mobile category subcategories list (Mobile)" },
|
||||||
|
{ "name": "Fetch mobile app categories configurations (Mobile)", "method": "GET", "url": "/live/api/v1/mob/utils/getappcategories", "description": "Fetch mobile app categories configurations (Mobile)" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "users",
|
||||||
|
"name": "Users",
|
||||||
|
"description": "Manage users, authentication, and roles across the platform.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Get all users (Web)", "method": "GET", "url": "/live/api/v1/web/users/getallusers?roleid=2&tenantid=8&pageno=1&pagesize=10&keyword=john", "description": "Get all users (Web)" },
|
||||||
|
{ "name": "Get a specific user profile by ID (Web)", "method": "GET", "url": "/live/api/v1/web/users/getusers?userid=12", "description": "Get a specific user profile by ID (Web)" },
|
||||||
|
{ "name": "Get a specific user profile by ID (Mobile)", "method": "GET", "url": "/live/api/v1/mob/users/getusers?userid=15", "description": "Get a specific user profile by ID (Mobile)" },
|
||||||
|
{ "name": "Operator/User orders board (Web)", "method": "GET", "url": "/live/api/v1/web/orders/user/getorders?appuserid=12&status=processing&pageno=1&pagesize=10", "description": "Operator/User orders board (Web)" },
|
||||||
|
{ "name": "Tenant Web Panel Login", "method": "POST", "url": "/live/api/v1/web/users/tenant/weblogin", "description": "Tenant Web Panel Login", "body": { "authname": "merchant_admin_01", "password": "PasswordSecurityHash99!" } },
|
||||||
|
{ "name": "General Application Login", "method": "POST", "url": "/live/api/v1/web/users/applogin", "description": "General Application Login", "body": { "authname": "system_operator", "password": "OperatorSafePasswordSecret", "deviceid": "device_uuid_8828b", "devicetype": "android" } },
|
||||||
|
{ "name": "Register New Web Staff Account", "method": "POST", "url": "/live/api/v1/web/users/create", "description": "Register New Web Staff Account", "body": { "authname": "tenant_staff_steve", "firstname": "Steve", "lastname": "Rogers", "password": "SteveSecurePassword12", "email": "steve.rogers@merchant.com", "dialcode": "+61", "contactno": "412345678", "roleid": 3, "pin": 1234, "address": "100 Flinders St", "suburb": "Melbourne", "city": "Melbourne", "state": "VIC", "postcode": "3000", "tenantid": 8, "locationid": 2, "applocationid": 1, "status": "active" } },
|
||||||
|
{ "name": "Update Web Staff User Details", "method": "PUT", "url": "/live/api/v1/web/users/update", "description": "Update Web Staff User Details", "body": { "userid": 15, "firstname": "Steve", "lastname": "Captain", "email": "steve.captain@merchant.com", "contactno": "412345678", "address": "200 Flinders St", "suburb": "Melbourne", "city": "Melbourne", "state": "VIC", "postcode": "3000", "status": "active" } },
|
||||||
|
{ "name": "Rider/Merchant Mobile App Login", "method": "POST", "url": "/live/api/v1/mob/users/tenant/login", "description": "Rider/Merchant Mobile App Login", "body": { "authname": "rider_john_01", "password": "RiderSecretKey" } },
|
||||||
|
{ "name": "Create Mobile Staff User", "method": "POST", "url": "/live/api/v1/mob/users/create", "description": "Create Mobile Staff User", "body": { "authname": "tenant_staff_steve", "firstname": "Steve", "lastname": "Rogers", "password": "SteveSecurePassword12", "email": "steve.rogers@merchant.com", "dialcode": "+61", "contactno": "412345678", "roleid": 3, "pin": 1234, "tenantid": 8, "locationid": 2, "applocationid": 1, "status": "active" } },
|
||||||
|
{ "name": "Update Mobile Staff Details", "method": "PUT", "url": "/live/api/v1/mob/users/update", "description": "Update Mobile Staff Details", "body": { "userid": 15, "firstname": "Steve", "lastname": "Captain", "email": "steve.captain@merchant.com", "contactno": "412345678", "status": "active" } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "partners",
|
||||||
|
"name": "Partners",
|
||||||
|
"description": "Partners, riders, shifts, locations, and log sheets.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Partner fleet orders board (Web)", "method": "GET", "url": "/live/api/v1/web/orders/partner/getorders?partnerid=1&status=processing&pageno=1&pagesize=10", "description": "Partner fleet orders board (Web)" },
|
||||||
|
{ "name": "Get active riders (Web)", "method": "GET", "url": "/live/api/v1/web/partners/getriders?partnerid=1&applocationid=1&userid=12&tenantid=8", "description": "Get active riders (Web)" },
|
||||||
|
{ "name": "Get partner profiles (Web)", "method": "GET", "url": "/live/api/v1/web/partners/getpartners?partnerid=1&applocationid=1&userid=12", "description": "Get partner profiles (Web)" },
|
||||||
|
{ "name": "Get rider shifts (Web)", "method": "GET", "url": "/live/api/v1/web/partners/getridershifts?applocationid=1", "description": "Get rider shifts (Web)" },
|
||||||
|
{ "name": "Get location configurations (Web)", "method": "GET", "url": "/live/api/v1/web/partners/getlocations?userid=12&configid=1", "description": "Get location configurations (Web)" },
|
||||||
|
{ "name": "Get rider log sheet (Web)", "method": "GET", "url": "/live/api/v1/web/partners/getriderlogs?partnerid=1&applocationid=1&fromdate=2026-05-20&todate=2026-05-20", "description": "Get rider log sheet (Web)" },
|
||||||
|
{ "name": "Get partner profiles (Mobile)", "method": "GET", "url": "/live/api/v1/mob/partners/getpartners?partnerid=1&applocationid=1&userid=12", "description": "Get partner profiles (Mobile)" },
|
||||||
|
{ "name": "Get rider log sheet (Mobile)", "method": "GET", "url": "/live/api/v1/mob/partners/getriderlogs?partnerid=1&applocationid=1&fromdate=2026-05-20&todate=2026-05-20", "description": "Get rider log sheet (Mobile)" },
|
||||||
|
{ "name": "Get rider operational info (Mobile)", "method": "GET", "url": "/live/api/v1/mob/partners/getriderinfo?userid=15", "description": "Get rider operational info (Mobile)" },
|
||||||
|
{ "name": "Get active riders list (Mobile)", "method": "GET", "url": "/live/api/v1/mob/partners/getriders?partnerid=1&applocationid=1&userid=15&tenantid=8", "description": "Get active riders list (Mobile)" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tenants",
|
||||||
|
"name": "Tenants",
|
||||||
|
"description": "Tenant accounts, locations, customers, pricing, onboarding.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Tenant orders board (Web)", "method": "GET", "url": "/live/api/v1/web/orders/tenant/getorders?tenantid=8&locationid=2&status=processing&pageno=1&pagesize=10", "description": "Tenant orders board (Web)" },
|
||||||
|
{ "name": "Get specific tenant store orders (Mobile)", "method": "GET", "url": "/live/api/v1/mob/orders/tenant/getorders?tenantid=8&locationid=2&pageno=1&pagesize=10", "description": "Get specific tenant store orders (Mobile)" },
|
||||||
|
{ "name": "Search registered tenants (Web)", "method": "GET", "url": "/live/api/v1/web/tenants/search?status=Active&keyword=Fresh", "description": "Search registered tenants (Web)" },
|
||||||
|
{ "name": "Search tenants by keyword (Web)", "method": "GET", "url": "/live/api/v1/web/tenants/searchbykeyword?keyword=daily", "description": "Search tenants by keyword (Web)" },
|
||||||
|
{ "name": "Get all active tenants catalog (Web)", "method": "GET", "url": "/live/api/v1/web/tenants/getalltenants?applocationid=1&status=Active&pageno=1&pagesize=10", "description": "Get all active tenants catalog (Web)" },
|
||||||
|
{ "name": "Get outlet locations assigned to a tenant (Web)", "method": "GET", "url": "/live/api/v1/web/tenants/gettenantlocations?tenantid=8", "description": "Get outlet locations assigned to a tenant (Web)" },
|
||||||
|
{ "name": "Retrieve delivery time slots config (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/gettenantslot", "description": "Retrieve delivery time slots config (Mobile)" },
|
||||||
|
{ "name": "Search tenants by keyword (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/searchbykeyword?keyword=grocery", "description": "Search tenants by keyword (Mobile)" },
|
||||||
|
{ "name": "Retrieve tenants associated with a customer (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/getcustomertenants?customerid=4082&tenant=0", "description": "Retrieve tenants associated with a customer (Mobile)" },
|
||||||
|
{ "name": "Get outlet locations linked to a tenant (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/gettenantlocations?tenantid=8", "description": "Get outlet locations linked to a tenant (Mobile)" },
|
||||||
|
{ "name": "Get logistics pricing slabs for a tenant (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/gettenantpricing?tenantid=8&applocationid=1", "description": "Get logistics pricing slabs for a tenant (Mobile)" },
|
||||||
|
{ "name": "Get staff members under a tenant store (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/getstaffs?tenantid=8", "description": "Get staff members under a tenant store (Mobile)" },
|
||||||
|
{ "name": "Get tenant detailed profile info (Mobile)", "method": "GET", "url": "/live/api/v1/mob/tenants/gettenantinfo?tenantid=8&locationid=2", "description": "Get tenant detailed profile info (Mobile)" },
|
||||||
|
{ "name": "Link Customer Profile to Tenant Store", "method": "POST", "url": "/live/api/v1/web/tenants/createtenantcustomer", "description": "Link Customer Profile to Tenant Store", "body": { "moduleid": 1, "tenantid": 8, "locationid": 2, "customerid": 4082, "customerlocationid": 554, "status": 1 } },
|
||||||
|
{ "name": "Create New Geofenced Store Location", "method": "POST", "url": "/live/api/v1/web/tenants/createlocation", "description": "Create New Geofenced Store Location", "body": { "tenantid": 8, "applocationid": 1, "moduleid": 1, "locationname": "Hawthorn Daily Fresh Store", "email": "hawthorn.store@merchant.com", "contactno": "399443322", "latitude": "-37.8222", "longitude": "145.0384", "address": "12 Glenferrie Rd", "suburb": "Hawthorn", "city": "Melbourne", "state": "VIC", "postcode": "3122", "opentime": "07:00:00", "closetime": "22:00:00", "partnerid": 1, "deliveryradius": 5000, "deliverymins": 30, "cancelsecs": 60, "status": "Active" } },
|
||||||
|
{ "name": "Update Store Location Configurations", "method": "PUT", "url": "/live/api/v1/web/tenants/updatelocation", "description": "Update Store Location Configurations", "body": { "locationid": 2, "tenantid": 8, "applocationid": 1, "locationname": "Richmond Daily Fresh Store", "email": "richmond.store@merchant.com", "contactno": "399887766", "latitude": "-37.8212", "longitude": "144.9984", "address": "Shop 4, 100 Church St", "suburb": "Richmond", "city": "Melbourne", "state": "VIC", "postcode": "3121", "opentime": "07:00:00", "closetime": "22:00:00", "deliveryradius": 8000, "deliverymins": 45, "cancelsecs": 120, "status": "Active" } },
|
||||||
|
{ "name": "Onboard New Tenant & Admin Profile", "method": "POST", "url": "/live/api/v1/mob/tenants/createtenantuser", "description": "Onboard New Tenant & Admin Profile (Joint Creation)", "body": { "tenantname": "Fresh Organic Greens", "configid": 1, "partnerid": 1, "moduleid": 1, "tenanttype": "Enterprise", "firstname": "Arthur", "primaryemail": "arthur@organicgreens.com", "primarycontact": "488999000", "categoryid": 2, "subcategoryid": 12, "address": "400 Chapel St", "suburb": "South Yarra", "city": "Melbourne", "state": "VIC", "postcode": "3141", "applocationid": 1, "approved": 1, "status": "Active" } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "customers",
|
||||||
|
"name": "Customers",
|
||||||
|
"description": "Customer accounts, addresses, support requests, and search.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Fetch customer profile by ID or Contact (Mobile)", "method": "GET", "url": "/live/api/v1/mob/customers/getbyid?customerid=4082&contactno=9876543210", "description": "Fetch customer profile by ID or Contact (Mobile)" },
|
||||||
|
{ "name": "Get customer saved address locations (Mobile)", "method": "GET", "url": "/live/api/v1/mob/customers/getcustomerlocation?customerid=4082", "description": "Get customer saved address locations (Mobile)" },
|
||||||
|
{ "name": "Get customer logged support requests (Mobile)", "method": "GET", "url": "/live/api/v1/mob/customers/getcustomerrequests?customerid=4082&pageno=1&pagesize=10", "description": "Get customer logged support requests (Mobile)" },
|
||||||
|
{ "name": "Search customer names under a tenant (Mobile)", "method": "GET", "url": "/live/api/v1/mob/customers/search?keyword=Jane&tenantid=8", "description": "Search customer names under a tenant (Mobile)" },
|
||||||
|
{ "name": "Retrieve customers linked to a tenant location (Mobile)", "method": "GET", "url": "/live/api/v1/mob/customers/gettenantcustomers?tenantid=8&locationid=2&pageno=1&pagesize=10", "description": "Retrieve customers linked to a tenant location (Mobile)" },
|
||||||
|
{ "name": "Retrieve merchant customers list (Web)", "method": "GET", "url": "/live/api/v1/web/customers/gettenantcustomers?tenantid=8&locationid=2&pageno=1&pagesize=10&keyword=jane", "description": "Retrieve merchant customers list (Web)" },
|
||||||
|
{ "name": "Individual consumer invoice histories (Web)", "method": "GET", "url": "/live/api/v1/web/orders/customer/getorders?customerid=4082&status=delivered&pageno=1&pagesize=10", "description": "Individual consumer invoice histories (Web)" },
|
||||||
|
{ "name": "Passwordless OTP Login (via Phone)", "method": "POST", "url": "/live/api/v1/mob/customers/login", "description": "Passwordless OTP Login (via Phone)", "body": { "contactno": "0499888777" } },
|
||||||
|
{ "name": "Register Customer Account", "method": "POST", "url": "/live/api/v1/mob/customers/create", "description": "Register Customer Account", "body": { "firstname": "Jane", "lastname": "Smith", "gender": "Female", "dob": "1994-11-20", "dialcode": "+61", "contactno": "499888777", "email": "jane.smith@gmail.com", "deviceid": "uuid_7728b991a", "devicetype": "ios", "authmode": 1, "address": "456 Oak Avenue", "suburb": "Richmond", "city": "Melbourne", "state": "VIC", "postcode": "3121", "latitude": "-37.8212", "longitude": "144.9984", "applocationid": 1, "status": 1 } },
|
||||||
|
{ "name": "Save New Geofenced Location Address", "method": "POST", "url": "/live/api/v1/mob/customers/createlocations", "description": "Save New Geofenced Location Address", "body": { "customerid": 4082, "address": "123 High Street", "suburb": "Prahran", "city": "Melbourne", "state": "VIC", "postcode": "3181", "latitude": "-37.8502", "longitude": "144.9924", "primaryaddress": 1, "status": 1 } },
|
||||||
|
{ "name": "Log Customer Support Ticket Request", "method": "POST", "url": "/live/api/v1/mob/customers/createcustomerrequest", "description": "Log Customer Support Ticket Request", "body": { "customerid": 4082, "tenantid": 8, "apptypeid": 1, "locationid": 2, "subject": "Delay in Morning Milk Delivery", "remarks": "Order scheduled for 7:00 AM hasn't arrived.", "status": 1 } },
|
||||||
|
{ "name": "Update Customer Profile Details", "method": "PUT", "url": "/live/api/v1/mob/customers/update", "description": "Update Customer Profile Details", "body": { "customerid": 4082, "firstname": "Jane", "lastname": "Miller", "email": "jane.miller@gmail.com", "contactno": "499888777", "status": 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "deliveries",
|
||||||
|
"name": "Deliveries",
|
||||||
|
"description": "Delivery dispatch, queues, summaries, and rider status tracking.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Get deliveries performance summaries (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/deliverysummary?tenantid=8&partnerid=1&userid=12&applocationid=1&locationid=2&fromdate=2026-05-20&todate=2026-05-20", "description": "Get deliveries performance summaries (Web)" },
|
||||||
|
{ "name": "Get daily delivery insights (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/getdeliveryinsight?tenantid=8", "description": "Get daily delivery insights (Web)" },
|
||||||
|
{ "name": "Get location deliveries summary (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/getlocationsummary?tenantid=8", "description": "Get location deliveries summary (Web)" },
|
||||||
|
{ "name": "Get deliveries financial report summary (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/getreportsummary?tenantid=8&partnerid=1&userid=12&applocationid=1&fromdate=2026-05-01&todate=2026-05-20", "description": "Get deliveries financial report summary (Web)" },
|
||||||
|
{ "name": "Get fleet rider summary metrics (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/getridersummary?applocationid=1&partnerid=1&tenantid=8&fromdate=2026-05-20&todate=2026-05-20", "description": "Get fleet rider summary metrics (Web)" },
|
||||||
|
{ "name": "Get master deliveries board (Web)", "method": "GET", "url": "/live/api/v1/web/deliveries/getdeliveries?tenantid=8&fromdate=2026-05-20&todate=2026-05-20", "description": "Get master deliveries board (Web)" },
|
||||||
|
{ "name": "Get mobile dispatch summaries (Mobile)", "method": "GET", "url": "/live/api/v1/mob/deliveries/deliverysummary?userid=15&fromdate=2026-05-20&todate=2026-05-20", "description": "Get mobile dispatch summaries (Mobile)" },
|
||||||
|
{ "name": "Get mobile deliveries board (Mobile)", "method": "GET", "url": "/live/api/v1/mob/deliveries/getdeliveries?userid=15&status=assigned", "description": "Get mobile deliveries board (Mobile)" },
|
||||||
|
{ "name": "Fetch rider active shift deliveries queue (Mobile)", "method": "GET", "url": "/live/api/v1/mob/deliveries/getdeliveryqueues?userid=15&fromdate=2026-05-20&todate=2026-05-20", "description": "Fetch rider active shift deliveries queue (Mobile)" },
|
||||||
|
{ "name": "Initialize Logistics Delivery Dispatch (Assign Rider)", "method": "POST", "url": "/live/api/v1/web/deliveries/createdeliveries", "description": "Initialize Logistics Delivery Dispatch", "body": [{ "orderheaderid": 2100, "applocationid": 1, "partnerid": 1, "tenantid": 8, "moduleid": 1, "locationid": 2, "userid": 15, "orderid": "ORD-19028-4", "deliverydate": "2026-05-20", "orderstatus": "assigned", "assigntime": "2026-05-20 12:10:00", "itemcount": 2, "orderamount": 12.58, "customerid": 4082, "pickupcustomer": "Central Merchant Warehouse", "pickupcontactno": "987654321", "pickuplocationid": 2, "pickupaddress": "Shop 4, Central Plaza, Melbourne", "pickuplat": "-37.8136", "pickuplon": "144.9631", "deliverycustomerid": 4082, "deliverylocationid": 554, "deliverycustomer": "Jane Smith", "deliverycontactno": "499888777", "deliveryaddress": "456 Oak Avenue, Richmond, VIC, 3121", "droplat": "-37.8212", "droplon": "144.9984", "deliverycharges": 3, "deliveryamt": 15.58, "deliverytype": "standard", "paymenttype": 1 }] },
|
||||||
|
{ "name": "Update Rider Pickup Status", "method": "PUT", "url": "/live/api/v1/web/deliveries/updatedelivery", "description": "Update Rider Pickup Status", "body": { "deliveryid": 8871, "orderheaderid": 2100, "userid": 15, "orderstatus": "picked", "pickuptime": "2026-05-20 12:20:00", "riderslat": "-37.8140", "riderslon": "144.9640" } },
|
||||||
|
{ "name": "Rider Update Dispatch Status (Delivered)", "method": "PUT", "url": "/live/api/v1/mob/deliveries/updatedelivery", "description": "Rider Update Dispatch Status (Delivered & GPS Tracking)", "body": { "deliveryid": 8871, "orderheaderid": 2100, "userid": 15, "orderstatus": "delivered", "deliverytime": "2026-05-20 12:45:00", "riderslat": "-37.8210", "riderslon": "144.9980", "actualkms": "4.2", "feedback": "Handed over safely.", "smsdelivery": 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "orders",
|
||||||
|
"name": "Orders",
|
||||||
|
"description": "Order boards, details, summaries, and status management.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Filtered dynamic orders board (Web)", "method": "GET", "url": "/live/api/v1/web/orders/getorders?tenantid=8&locationid=2&status=processing&pageno=1&pagesize=10", "description": "Filtered dynamic orders board (Web)" },
|
||||||
|
{ "name": "System Admin orders board (Web)", "method": "GET", "url": "/live/api/v1/web/orders/admin/getorders?applocationid=1&status=processing&pageno=1&pagesize=10", "description": "System Admin orders board (Web)" },
|
||||||
|
{ "name": "Get order dashboard stats summary (Web)", "method": "GET", "url": "/live/api/v1/web/orders/getordersummary?tenantid=8&fromdate=2026-05-01&todate=2026-05-20", "description": "Get order dashboard stats summary (Web)" },
|
||||||
|
{ "name": "Get location orders summary (Web)", "method": "GET", "url": "/live/api/v1/web/orders/getlocationsummary?tenantid=8", "description": "Get location orders summary (Web)" },
|
||||||
|
{ "name": "Get annual orders insights analytics (Web)", "method": "GET", "url": "/live/api/v1/web/orders/getorderinsight?tenantid=8", "description": "Get annual orders insights analytics (Web)" },
|
||||||
|
{ "name": "Get order detailed lines (Web)", "method": "GET", "url": "/live/api/v1/web/orders/getorderdetails?orderheaderid=2099", "description": "Get order detailed lines (Web)" },
|
||||||
|
{ "name": "Get customer order history (Mobile)", "method": "GET", "url": "/live/api/v1/mob/orders/getcustomerorders?customerid=4082&pageno=1&pagesize=10", "description": "Get customer order history (Mobile)" },
|
||||||
|
{ "name": "Get mobile order detailed lines (Mobile)", "method": "GET", "url": "/live/api/v1/mob/orders/getorderdetails?orderheaderid=2099", "description": "Get mobile order detailed lines (Mobile)" },
|
||||||
|
{ "name": "Create New Web Order", "method": "POST", "url": "/live/api/v1/web/orders/createorder", "description": "Create New Web Order (Flat JSON Format)", "body": { "tenantid": 8, "locationid": 2, "applocationid": 1, "moduleid": 1, "customerid": 4082, "orderstatus": "pending", "deliverytype": "standard", "deliverytime": "2026-05-20 18:00:00", "pickupaddress": "Shop 4, Central Plaza, Melbourne", "pickuplat": "-37.8136", "pickuplong": "144.9631", "pickupcustomer": "Central Plaza Merchant", "pickupcontactno": "399887766", "deliveryaddress": "Apt 4B, Sunset Boulevard, Richmond", "deliverylat": "-37.8212", "deliverylong": "144.9984", "orderamount": 11.48, "taxamount": 1.1, "ordervalue": 12.58, "itemcount": 2, "paymenttype": 1, "paymentstatus": 0, "deliverycharge": 3, "items": [{ "productid": 105, "productname": "Organic Whole Milk 1L", "orderqty": 2, "price": 3.99, "taxpercentage": 10, "taxamount": 0.8, "productsumprice": 7.98 }] } },
|
||||||
|
{ "name": "Update Order Status & Financial Flag", "method": "PUT", "url": "/live/api/v1/web/orders/updateorder", "description": "Update Order Status & Financial Flag", "body": { "orderheaderid": 2099, "orderstatus": "ready", "paymentstatus": 1, "remarks": "Order packed and waiting for rider assignment." } },
|
||||||
|
{ "name": "Create Mobile Order", "method": "POST", "url": "/live/api/v1/mob/orders/createorder", "description": "Create Mobile Order (Wrapped JSON Format)", "body": { "orders": { "tenantid": 8, "locationid": 2, "applocationid": 1, "moduleid": 1, "customerid": 4082, "orderstatus": "pending", "deliverytype": "standard", "deliverytime": "2026-05-20 18:00:00", "pickupaddress": "Shop 4, Central Plaza, Melbourne", "orderamount": 11.48, "taxamount": 1.1, "ordervalue": 12.58, "itemcount": 2, "paymenttype": 1, "paymentstatus": 0, "deliverycharge": 3, "items": [{ "productid": 105, "productname": "Organic Whole Milk 1L", "orderqty": 2, "price": 3.99, "taxpercentage": 10, "taxamount": 0.8, "productsumprice": 7.98 }] } } },
|
||||||
|
{ "name": "Mobile Update Order Status", "method": "PUT", "url": "/live/api/v1/mob/orders/updateorder", "description": "Mobile Update Order Status", "body": { "orderheaderid": 2099, "orderstatus": "ready", "paymentstatus": 1, "remarks": "Order packed and waiting for rider assignment." } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "products",
|
||||||
|
"name": "Products",
|
||||||
|
"description": "Product catalog, stock management, variants, and outlet inventory.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Get product subcategories (Web)", "method": "GET", "url": "/live/api/v1/web/products/getproductsubcategories?categoryid=2&tenantid=8", "description": "Get product subcategories (Web)" },
|
||||||
|
{ "name": "Get products stock counts (Web)", "method": "GET", "url": "/live/api/v1/web/products/getproductscount?tenantid=8&categoryid=2&subcategoryid=12&approve=1", "description": "Get products stock counts (Web)" },
|
||||||
|
{ "name": "Get all global categories (Web)", "method": "GET", "url": "/live/api/v1/web/products/getproductcategories", "description": "Get all global categories (Web)" },
|
||||||
|
{ "name": "Get specific product variants (Web)", "method": "GET", "url": "/live/api/v1/web/products/getproductvariants?tenantid=8&subcategoryid=12", "description": "Get specific product variants (Web)" },
|
||||||
|
{ "name": "Get master catalog listings (Web)", "method": "GET", "url": "/live/api/v1/web/products/getcatalougeproducts?tenantid=8&locationid=2&subcategoryid=12&keyword=&pageno=1&pagesize=10", "description": "Get master catalog listings (Web)" },
|
||||||
|
{ "name": "Get live stocks catalog (Web)", "method": "GET", "url": "/live/api/v1/web/products/getproductstocks?tenantid=8&locationid=2", "description": "Get live stocks catalog (Web)" },
|
||||||
|
{ "name": "Get dynamic stock statement ledger (Web)", "method": "GET", "url": "/live/api/v1/web/products/getstockstatement?tenantid=8&locationid=2&subcategoryid=12&pageno=1&pagesize=10&keyword=", "description": "Get dynamic stock statement ledger (Web)" },
|
||||||
|
{ "name": "Get outlet geofenced inventory (Web)", "method": "GET", "url": "/live/api/v1/web/products/getlocationproducts?tenantid=8&locationid=2&subcategoryid=12&pageno=1&pagesize=10", "description": "Get outlet geofenced inventory (Web)" },
|
||||||
|
{ "name": "Master products search board (Web)", "method": "GET", "url": "/live/api/v1/web/products/getallproducts?tenantid=8&locationid=2&keyword=milk&pageno=1&pagesize=10", "description": "Master products search board (Web)" },
|
||||||
|
{ "name": "Get product details by variant ID (Mobile)", "method": "GET", "url": "/live/api/v1/mob/products/getproductbyvariant?tenantid=8&variantid=4", "description": "Get product details by variant ID (Mobile)" },
|
||||||
|
{ "name": "Get product subcategories (Mobile)", "method": "GET", "url": "/live/api/v1/mob/products/getproductsubcategories?categoryid=2&tenantid=8", "description": "Get product subcategories (Mobile)" },
|
||||||
|
{ "name": "Search product catalog (Mobile)", "method": "GET", "url": "/live/api/v1/mob/products/getallproducts?keyword=milk&pageno=1&pagesize=10", "description": "Search product catalog (Mobile)" },
|
||||||
|
{ "name": "Get mobile geofenced outlet products (Mobile)", "method": "GET", "url": "/live/api/v1/mob/products/getlocationproducts?tenantid=8&locationid=2&pageno=1&pagesize=20", "description": "Get mobile geofenced outlet products (Mobile)" },
|
||||||
|
{ "name": "Add Multi-Product Stock Entry", "method": "POST", "url": "/live/api/v1/web/products/createproductstock", "description": "Add Multi-Product Stock Entry", "body": [{ "tenantid": 8, "locationid": 2, "productid": 105, "quantity": 150, "stocktype": "credit", "status": "active" }, { "tenantid": 8, "locationid": 2, "productid": 109, "quantity": 80, "stocktype": "credit", "status": "active" }] },
|
||||||
|
{ "name": "Create Master Product Catalog Item", "method": "POST", "url": "/live/api/v1/web/products/create", "description": "Create Master Product Catalog Item", "body": { "applocationid": 1, "tenantid": 8, "categoryid": 2, "subcategoryid": 12, "productname": "Fresh Cow Milk 1L", "productunit": "Litre", "unitvalue": "1", "productcost": 1.8, "retailprice": 3.5, "taxpercent": 5, "productstock": 100, "productstatus": "available", "approve": 1 } },
|
||||||
|
{ "name": "Update Master Product Details", "method": "PUT", "url": "/live/api/v1/web/products/update", "description": "Update Master Product Details", "body": { "productid": 105, "productname": "Organic Farm Cow Milk 1L", "productcost": 1.95, "retailprice": 3.75, "productstock": 120, "productstatus": "available" } },
|
||||||
|
{ "name": "Purge Master Product Catalog Entry", "method": "DELETE", "url": "/live/api/v1/web/products/delete?productid=105", "description": "Purge Master Product Catalog Entry" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "invoice",
|
||||||
|
"name": "Invoice",
|
||||||
|
"description": "Invoice insights and billing analytics.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Get invoice insights for a tenant", "method": "GET", "url": "/live/api/v1/web/invoice/getinvoiceinsight?tenantid=8", "description": "Retrieve invoice insights and statistics for a tenant." }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "payments",
|
||||||
|
"name": "Payments",
|
||||||
|
"description": "Payment requests and settlement records.",
|
||||||
|
"endpoints": [
|
||||||
|
{ "name": "Get payment requests for a partner", "method": "GET", "url": "/live/api/v1/web/payments/requests/getpaymentrequest?partnerid=44&status=1", "description": "List payment requests for a partner by status." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -8,12 +8,18 @@
|
|||||||
body {
|
body {
|
||||||
@apply bg-slate-50 text-slate-800 font-sans antialiased selection:bg-brand-500/30 selection:text-brand-900;
|
@apply bg-slate-50 text-slate-800 font-sans antialiased selection:bg-brand-500/30 selection:text-brand-900;
|
||||||
}
|
}
|
||||||
|
html.dark body {
|
||||||
|
@apply bg-dark-900 text-slate-300 selection:bg-brand-500/30 selection:text-brand-100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.glass {
|
.glass {
|
||||||
@apply bg-white/70 backdrop-blur-md border border-white/40 shadow-glass;
|
@apply bg-white/70 backdrop-blur-md border border-white/40 shadow-glass;
|
||||||
}
|
}
|
||||||
|
html.dark .glass {
|
||||||
|
@apply bg-dark-800/80 border-white/5;
|
||||||
|
}
|
||||||
|
|
||||||
.dark-glass {
|
.dark-glass {
|
||||||
@apply bg-dark-900/90 backdrop-blur-xl border border-white/5;
|
@apply bg-dark-900/90 backdrop-blur-xl border border-white/5;
|
||||||
@@ -40,9 +46,26 @@
|
|||||||
@apply bg-slate-700 hover:bg-slate-600;
|
@apply bg-slate-700 hover:bg-slate-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html.dark ::-webkit-scrollbar-thumb {
|
||||||
|
@apply bg-dark-600 hover:bg-slate-600;
|
||||||
|
}
|
||||||
|
|
||||||
/* Background Pattern */
|
/* Background Pattern */
|
||||||
.bg-grid-pattern {
|
.bg-grid-pattern {
|
||||||
background-image: linear-gradient(to right, #f1f5f9 1px, transparent 1px),
|
background-image: linear-gradient(to right, #f1f5f9 1px, transparent 1px),
|
||||||
linear-gradient(to bottom, #f1f5f9 1px, transparent 1px);
|
linear-gradient(to bottom, #f1f5f9 1px, transparent 1px);
|
||||||
background-size: 40px 40px;
|
background-size: 40px 40px;
|
||||||
}
|
}
|
||||||
|
html.dark .bg-grid-pattern {
|
||||||
|
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide scrollbar utility (used in sidebar / panes) */
|
||||||
|
.scrollbar-hide {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
26
src/lib/highlight.js
Normal file
26
src/lib/highlight.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const TOKEN = /("(?:\\u[a-fA-F0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(?:true|false|null)\b|-?\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?)/g
|
||||||
|
|
||||||
|
function escapeHtml(s) {
|
||||||
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function highlightJSON(value) {
|
||||||
|
let text
|
||||||
|
try {
|
||||||
|
text = JSON.stringify(value, null, 2)
|
||||||
|
} catch {
|
||||||
|
text = String(value)
|
||||||
|
}
|
||||||
|
if (typeof text !== 'string') text = String(text)
|
||||||
|
return escapeHtml(text).replace(TOKEN, (match) => {
|
||||||
|
let cls = 'text-amber-300'
|
||||||
|
if (/^"/.test(match)) {
|
||||||
|
cls = /:$/.test(match) ? 'text-sky-300' : 'text-emerald-300'
|
||||||
|
} else if (match === 'true' || match === 'false') {
|
||||||
|
cls = 'text-violet-300'
|
||||||
|
} else if (match === 'null') {
|
||||||
|
cls = 'text-rose-300'
|
||||||
|
}
|
||||||
|
return `<span class="${cls}">${match}</span>`
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
|
darkMode: 'class',
|
||||||
content: [
|
content: [
|
||||||
"./index.html",
|
"./index.html",
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
|
|||||||
39
test_portal.py
Normal file
39
test_portal.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
import time
|
||||||
|
|
||||||
|
URL = "https://developer.nearledaily.com/"
|
||||||
|
|
||||||
|
def test_portal():
|
||||||
|
print(f"Testing connectivity to {URL}...\n")
|
||||||
|
try:
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
# Send a standard GET request with a user-agent
|
||||||
|
req = urllib.request.Request(URL, headers={'User-Agent': 'Mozilla/5.0'})
|
||||||
|
with urllib.request.urlopen(req) as response:
|
||||||
|
status_code = response.getcode()
|
||||||
|
html = response.read().decode('utf-8')
|
||||||
|
duration = round((time.time() - start_time) * 1000, 2)
|
||||||
|
|
||||||
|
if status_code == 200:
|
||||||
|
print(f"[SUCCESS] Server responded with HTTP 200 OK in {duration}ms!")
|
||||||
|
|
||||||
|
# Check for specific title tags or branding we added
|
||||||
|
if "NearleDaily API" in html or "nearledaily-docs" in html.lower() or "nearledaily" in html.lower():
|
||||||
|
print("[SUCCESS] Found NearleDaily branding in the page HTML. The app is serving the correct files!")
|
||||||
|
else:
|
||||||
|
print("[WARNING] Server responded with 200 OK, but couldn't find the expected React app HTML.")
|
||||||
|
else:
|
||||||
|
print(f"[ERROR] Server responded with unexpected status code: {status_code}")
|
||||||
|
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(f"[HTTP ERROR] The server responded, but returned an error status code: {e.code}")
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
print(f"[NETWORK ERROR] Failed to reach the server. Reason: {e.reason}")
|
||||||
|
print("Hint: If you just changed the DNS or Coolify port, wait a minute for it to apply/propagate.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[UNEXPECTED ERROR] {str(e)}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_portal()
|
||||||
Reference in New Issue
Block a user