feature/get-places-api #2
17
.babelrc
Normal file
17
.babelrc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"targets": {
|
||||||
|
"node": "current",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
["@babel/preset-react", {
|
||||||
|
"runtime": "automatic"
|
||||||
|
}],
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
],
|
||||||
|
"plugins": ["babel-plugin-transform-import-meta"]
|
||||||
|
}
|
10
.env.development
Normal file
10
.env.development
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
VITE_API_ORIGIN = https://admin.dev.dipal.ru/api/v1
|
||||||
|
VITE_API_AUTH_ORIGIN = https://auth.dev.dipal.ru/api/v1/auth
|
||||||
|
VITE_API_AUTH_PHONENUMBER = /start-challenge
|
||||||
|
VITE_API_AUTH_LOGIN = /login
|
||||||
|
VITE_API_AUTH_REFRESH = /refresh-token
|
||||||
|
VITE_API_CREATE_MEMBER = /user_place/members
|
||||||
|
VITE_API_PLACES = /place
|
||||||
|
VITE_API_USERS = /profile
|
||||||
|
VITE_API_USERS_ACCOUNT = /account
|
||||||
|
VITE_API_USERS_PROFILE = /profile
|
11
.eslintignore
Normal file
11
.eslintignore
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/node_modules
|
||||||
|
/public
|
||||||
|
/dist
|
||||||
|
vite.config.ts
|
||||||
|
.eslintrc.js
|
||||||
|
/build
|
||||||
|
/src/vite-env.d.ts
|
||||||
|
tailwind.config.cjs
|
||||||
|
postcss.config.cjs
|
||||||
|
fileMock.js
|
||||||
|
jest.config.js
|
83
.eslintrc.json
Normal file
83
.eslintrc.json
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"version": "detect"
|
||||||
|
},
|
||||||
|
"import/resolver": {
|
||||||
|
"alias": {
|
||||||
|
"map": [["~", "./src"]],
|
||||||
|
"extensions": [".js",".ts",".tsx", ".d.ts", ".json"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"airbnb",
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"plugin:jest/recommended",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
|
"overrides": [],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["react", "@typescript-eslint", "jest", "prettier"],
|
||||||
|
"rules": {
|
||||||
|
"object-curly-spacing": ["error", "always"],
|
||||||
|
"import/extensions": [
|
||||||
|
"error",
|
||||||
|
"ignorePackages",
|
||||||
|
{
|
||||||
|
"js": "never",
|
||||||
|
"jsx": "never",
|
||||||
|
"ts": "never",
|
||||||
|
"tsx": "never"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
||||||
|
"class-methods-use-this": "off",
|
||||||
|
"import/no-import-module-exports": "off",
|
||||||
|
"react/require-default-props": "off",
|
||||||
|
"import/prefer-default-export": "off",
|
||||||
|
"jsx-a11y/click-events-have-key-events": "off",
|
||||||
|
"jsx-a11y/no-static-element-interactions": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "error",
|
||||||
|
"@typescript-eslint/no-shadow": "error",
|
||||||
|
"no-shadow": "off",
|
||||||
|
"no-return-await": "off",
|
||||||
|
"import/order": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"pathGroups": [
|
||||||
|
{
|
||||||
|
"pattern": "~/**",
|
||||||
|
"group": "external"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prettier/prettier": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"usePrettierrc": true,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"endOfLine": "auto"
|
||||||
|
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"jest/valid-title": "off",
|
||||||
|
"react/button-has-type": "off",
|
||||||
|
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".ts", ".tsx"] }],
|
||||||
|
"react/react-in-jsx-scope": "off",
|
||||||
|
"@typescript-eslint/no-namespace": "off"
|
||||||
|
}
|
||||||
|
}
|
5
.husky/pre-push
Executable file
5
.husky/pre-push
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npm run test && npm run lint
|
||||||
|
npm run test && npm run lint
|
13
.prettierrc.json
Normal file
13
.prettierrc.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 120,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"endOfLine":"auto",
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always"
|
||||||
|
}
|
@ -8,5 +8,7 @@ export default {
|
|||||||
"\\.(css|less)$": "identity-obj-proxy",
|
"\\.(css|less)$": "identity-obj-proxy",
|
||||||
"^~(.*)$": "<rootDir>/src$1"
|
"^~(.*)$": "<rootDir>/src$1"
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: ['<rootDir>/node_modules/'],
|
transformIgnorePatterns: [
|
||||||
|
"node_modules/(?!(spacetime)/)"
|
||||||
|
]
|
||||||
}
|
}
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -7704,6 +7704,14 @@
|
|||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"swr": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==",
|
||||||
|
"requires": {
|
||||||
|
"use-sync-external-store": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"symbol-tree": {
|
"symbol-tree": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||||
|
11
package.json
11
package.json
@ -8,7 +8,7 @@
|
|||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint --fix --ignore-path .eslintignore --ignore-pattern \"!**/.*\" .",
|
"lint": "eslint --fix --ignore-path .eslintignore --ignore-pattern \"!**/.*\" .",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install && husky add .husky/pre-push \"npm run test && npm run lint\"",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"tsc": "tsc"
|
"tsc": "tsc"
|
||||||
},
|
},
|
||||||
@ -18,16 +18,17 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"react-router-dom": "^6.9.0"
|
"react-router-dom": "^6.9.0",
|
||||||
|
"swr": "^2.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "^7.20.2",
|
"@babel/preset-env": "^7.21.5",
|
||||||
"@babel/preset-react": "^7.18.6",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/preset-typescript": "^7.21.0",
|
"@babel/preset-typescript": "^7.21.5",
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^14.0.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
"@testing-library/user-event": "^14.4.3",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"@types/jest": "^29.4.0",
|
"@types/jest": "^29.5.1",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.27",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.10",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
||||||
|
15
public/assets/icons/logo-black.svg
Normal file
15
public/assets/icons/logo-black.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<svg width="198" height="48" viewBox="0 0 198 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M29.2175 33.8487H23.577C21.0802 33.8442 18.6869 32.8468 16.9213 31.075C15.1558 29.3032 14.162 26.9014 14.1575 24.3957V18.7353L13.255 17.8296C12.5503 17.1065 11.7076 16.5333 10.7773 16.1443C9.84695 15.7553 8.84804 15.5584 7.84021 15.5654C6.83237 15.5584 5.83346 15.7553 4.90313 16.1443C3.97279 16.5333 3.13011 17.1065 2.42539 17.8296L2.25617 17.9428C1.54128 18.6542 0.973841 19.5007 0.586605 20.4334C0.199369 21.3661 0 22.3664 0 23.3768C0 24.3872 0.199369 25.3876 0.586605 26.3203C0.973841 27.2529 1.54128 28.0994 2.25617 28.8109L19.1211 45.7356C20.5661 47.1651 22.507 47.9767 24.5359 47.9998C25.5437 48.0068 26.5426 47.8099 27.473 47.4209C28.4033 47.0319 29.246 46.4587 29.9507 45.7356L30.0635 45.6224C31.4998 44.1699 32.3058 42.2065 32.3058 40.1601C32.3058 38.1137 31.4998 36.1503 30.0635 34.6977L29.2175 33.8487Z" fill="#9E00C5"/>
|
||||||
|
<path d="M40.2726 16.528H33.1657V24.396C33.1584 25.9067 32.7911 27.3938 32.0944 28.733C31.3978 30.0722 30.3919 31.2247 29.1609 32.0943H40.329C42.363 32.0928 44.3133 31.2812 45.7516 29.8378C47.1898 28.3945 47.9985 26.4373 48 24.396V24.2262C47.9749 22.1826 47.1509 20.2306 45.7056 18.7907C44.2602 17.3508 42.3092 16.5382 40.2726 16.528Z" fill="#9E00C5"/>
|
||||||
|
<path d="M18.162 18.7924C17.4415 19.4996 16.8704 20.3453 16.4827 21.2789C16.0951 22.2125 15.8989 23.215 15.9058 24.2264V24.3962C15.9073 26.4374 16.716 28.3947 18.1543 29.838C19.5925 31.2814 21.5428 32.0929 23.5768 32.0944H23.746C25.7801 32.0929 27.7303 31.2814 29.1686 29.838C30.6069 28.3947 31.4156 26.4374 31.417 24.3962V16.5282H23.5768C22.569 16.5212 21.5701 16.7181 20.6398 17.1071C19.7094 17.4961 18.8667 18.0693 18.162 18.7924Z" fill="#9E00C5"/>
|
||||||
|
<path d="M16.9778 17.604C18.7246 15.8387 21.0981 14.8412 23.5771 14.8304H31.4173V7.69822C31.4158 5.65699 30.6072 3.69978 29.1689 2.25641C27.7306 0.813041 25.7804 0.00149926 23.7463 0H23.5771C21.5431 0.00149926 19.5928 0.813041 18.1546 2.25641C16.7163 3.69978 15.9076 5.65699 15.9061 7.69822V18.9059C16.2004 18.4234 16.5612 17.9851 16.9778 17.604Z" fill="#9E00C5"/>
|
||||||
|
<path d="M55 16.7575H57.7267V31.1991H55V16.7575ZM65.3874 31.1991L59.3281 25.6811C59.0732 25.429 58.8757 25.1254 58.7488 24.7907C58.6218 24.456 58.5685 24.0981 58.5923 23.7412C58.6196 23.1431 58.8659 22.5756 59.2848 22.1461L64.7815 16.7144H68.2006L61.9249 22.6635C61.5787 23.0083 61.2324 23.2239 61.2324 23.7412C61.2324 24.3447 61.6652 24.7327 62.0981 25.0776L68.9797 31.1991H65.3874Z" fill="black"/>
|
||||||
|
<path d="M83.3027 24C83.3027 29.8629 81.2685 31.4148 75.8584 31.4148C70.4483 31.4148 68.4141 29.8629 68.4141 24C68.4141 18.1371 70.4915 16.5852 75.8584 16.5852C81.2252 16.5852 83.3027 18.1371 83.3027 24ZM75.8584 29.2163C79.4074 29.2163 80.4894 28.1385 80.4894 24C80.4894 19.8615 79.4074 18.7838 75.8584 18.7838C72.3093 18.7838 71.2273 19.8615 71.2273 24C71.2273 28.1385 72.2661 29.2163 75.8584 29.2163Z" fill="black"/>
|
||||||
|
<path d="M96.2439 29.6474C95.8111 30.7682 95.4216 31.3717 94.1665 31.3717C92.9113 31.3717 92.5218 30.7682 92.089 29.6474L88.4101 19.9908C88.3668 19.8184 88.1937 19.5166 88.0639 19.5166C87.8475 19.5166 87.8475 19.9046 87.8475 19.9477L87.8908 31.1993H85.1641V18.482C85.1641 17.1456 86.073 16.5852 87.5012 16.5852C89.1459 16.5852 89.6653 17.4474 90.0548 18.4389L93.8202 28.0954C93.9501 28.3972 94.0799 28.6127 94.2097 28.6127C94.3396 28.6127 94.4694 28.3972 94.5993 28.0954L98.3647 18.4389C98.7542 17.4474 99.2736 16.5852 100.918 16.5852C102.39 16.5852 103.255 17.1456 103.255 18.482V31.1993H100.529L100.615 19.9477C100.615 19.5598 100.442 19.5166 100.356 19.5166C100.269 19.5166 100.053 19.8184 100.009 19.9908L96.2439 29.6474Z" fill="black"/>
|
||||||
|
<path d="M115.163 16.7578V17.9218H117.63C121.785 17.9218 122.607 20.1203 122.607 23.8278C122.607 27.5352 121.742 29.7768 117.63 29.7768H115.163V31.1995H112.436V29.7768H109.969C105.815 29.7768 104.992 27.5352 104.992 23.8278C104.992 20.1203 105.815 17.9218 109.969 17.9218H112.436V16.7578H115.163ZM112.436 20.1203H110.792C108.282 20.1203 107.805 21.155 107.805 23.8709C107.805 26.5868 108.282 27.7076 110.792 27.7076H112.436V20.1203ZM116.808 27.6645C119.318 27.6645 119.794 26.5436 119.794 23.8278C119.794 21.1119 119.318 20.0772 116.808 20.0772H115.163V27.6214L116.808 27.6645Z" fill="black"/>
|
||||||
|
<path d="M138.967 24C138.967 29.8629 136.933 31.4148 131.522 31.4148C126.112 31.4148 124.078 29.8629 124.078 24C124.078 18.1371 126.156 16.5852 131.522 16.5852C136.889 16.5852 138.967 18.1371 138.967 24ZM131.522 29.2163C135.071 29.2163 136.153 28.1385 136.153 24C136.153 19.8615 135.071 18.7838 131.522 18.7838C127.973 18.7838 126.891 19.8615 126.891 24C126.891 28.1385 127.93 29.2163 131.522 29.2163Z" fill="black"/>
|
||||||
|
<path d="M140.781 18.9133C140.781 17.2751 141.647 16.7578 142.902 16.7578H150.13C153.246 16.7578 153.809 18.9133 153.809 21.4136C153.809 23.914 153.246 26.1126 150.13 26.1126H143.551V31.1995H140.825V18.9133H140.781ZM148.745 23.914C150.606 23.914 150.952 23.0518 150.952 21.4136C150.952 19.7755 150.606 18.9564 148.745 18.9564H144.547C143.724 18.9564 143.508 19.1719 143.508 19.991V23.9571H148.745V23.914Z" fill="black"/>
|
||||||
|
<path d="M160.256 31.1995V18.9133H154.586V16.7578H168.652V18.9133H162.982V31.1995H160.256Z" fill="black"/>
|
||||||
|
<path d="M181.557 31.1995H172.035C170.78 31.1995 169.914 30.6821 169.914 29.044V18.9133C169.914 17.2751 170.78 16.7578 172.035 16.7578H181.47V18.9133H173.679C172.857 18.9133 172.641 19.1288 172.641 19.9479V22.75H181.254V24.9055H172.641V28.0094C172.641 28.8284 172.857 29.044 173.679 29.044H181.557V31.1995Z" fill="black"/>
|
||||||
|
<path d="M187.958 17.9647C188.218 17.3181 188.651 16.5852 190.166 16.5852C191.68 16.5852 192.113 17.275 192.373 17.9647L197.999 31.1993H195.1L190.512 19.646C190.469 19.4735 190.425 19.2149 190.166 19.2149C189.906 19.2149 189.863 19.4735 189.819 19.646L185.275 31.1993H182.375L187.958 17.9647Z" fill="black"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1,9 @@
|
|||||||
|
type Places = {
|
||||||
|
placeType: string;
|
||||||
|
name: string;
|
||||||
|
qr: null | string;
|
||||||
|
id: string;
|
||||||
|
parentId: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Places;
|
21
src/business-logic/core/places/common/model/placesModel.ts
Normal file
21
src/business-logic/core/places/common/model/placesModel.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import Places from '../entity/placeEntity';
|
||||||
|
|
||||||
|
class PlacesModel {
|
||||||
|
private placesList: Places[];
|
||||||
|
|
||||||
|
private modelTitle = 'places';
|
||||||
|
|
||||||
|
constructor(data: Places[]) {
|
||||||
|
this.placesList = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): Places[] {
|
||||||
|
return this.placesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitle(): string {
|
||||||
|
return this.modelTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlacesModel;
|
@ -0,0 +1,16 @@
|
|||||||
|
import PlacesModel from '../../../common/model/placesModel';
|
||||||
|
import getPlacesRO from '../response-object/getPlacesRO';
|
||||||
|
import { GetPlacesResponse } from '../response-object/protocols';
|
||||||
|
|
||||||
|
const getPlacesRepo = async (httpHandler: () => Promise<GetPlacesResponse>) => {
|
||||||
|
// call httpHandler
|
||||||
|
const placesResponse = await httpHandler();
|
||||||
|
// user response object to turn it to the data that we want
|
||||||
|
const placesData = getPlacesRO(placesResponse);
|
||||||
|
// make model
|
||||||
|
const placesModel = new PlacesModel(placesData);
|
||||||
|
// return the model
|
||||||
|
return placesModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getPlacesRepo;
|
@ -0,0 +1,5 @@
|
|||||||
|
import PlacesModel from '../../../common/model/placesModel';
|
||||||
|
|
||||||
|
type IGetPlacesRepo = () => Promise<PlacesModel>;
|
||||||
|
|
||||||
|
export default IGetPlacesRepo;
|
@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
import { GetPlacesRO, GetPlacesResponse } from './protocols';
|
||||||
|
|
||||||
|
const getPlacesRO = (placesResponse: GetPlacesResponse): GetPlacesRO => {
|
||||||
|
return placesResponse.map((placeResponse) => {
|
||||||
|
return {
|
||||||
|
id: placeResponse._id,
|
||||||
|
placeType: placeResponse.place_type,
|
||||||
|
name: placeResponse.name,
|
||||||
|
parentId: placeResponse.place_type,
|
||||||
|
availableServices: placeResponse.available_services,
|
||||||
|
createdAt: placeResponse.createdAt,
|
||||||
|
updatedAt: placeResponse.updatedAt,
|
||||||
|
qr: null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getPlacesRO;
|
@ -0,0 +1,18 @@
|
|||||||
|
import Places from '../../../common/entity/placeEntity';
|
||||||
|
|
||||||
|
export type GetPlacesResponse = {
|
||||||
|
_id: string;
|
||||||
|
place_type: string;
|
||||||
|
name: string;
|
||||||
|
parent_id: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
available_services: string[];
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export type GetPlacesRO = Places[] &
|
||||||
|
{
|
||||||
|
availableServices: string[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}[];
|
3
src/business-logic/core/places/get-places/index.ts
Normal file
3
src/business-logic/core/places/get-places/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import getPlaces from './infra/getPlacesInfra';
|
||||||
|
|
||||||
|
export default getPlaces;
|
@ -0,0 +1,15 @@
|
|||||||
|
import getPlacesRepo from '../data/repository/GetPlacesRepo';
|
||||||
|
import IGetPlacesRepo from '../data/repository/IGetPlacesRepo';
|
||||||
|
import GettingPlacesUsecase from '../usecase/getPlaceUsecase';
|
||||||
|
import { IgetPlacesInfra, getPlacesReturnType } from './protocols';
|
||||||
|
|
||||||
|
const getPlaces = ({ httpHandler }: IgetPlacesInfra): getPlacesReturnType => {
|
||||||
|
// get httpHandler
|
||||||
|
const repository: IGetPlacesRepo = () => getPlacesRepo(httpHandler);
|
||||||
|
// connet usecase and repository
|
||||||
|
const usecase = new GettingPlacesUsecase(repository);
|
||||||
|
// return method to use
|
||||||
|
return () => usecase.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getPlaces;
|
@ -0,0 +1,8 @@
|
|||||||
|
import PlacesModel from '../../common/model/placesModel';
|
||||||
|
import { GetPlacesResponse } from '../data/response-object/protocols';
|
||||||
|
|
||||||
|
export interface IgetPlacesInfra {
|
||||||
|
httpHandler: () => Promise<GetPlacesResponse>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type getPlacesReturnType = () => Promise<PlacesModel>;
|
5
src/business-logic/core/places/get-places/port.ts
Normal file
5
src/business-logic/core/places/get-places/port.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { getPlacesReturnType, type IgetPlacesInfra } from './infra/protocols';
|
||||||
|
|
||||||
|
export default IgetPlacesInfra;
|
||||||
|
|
||||||
|
export type getPlacesReturnPort = getPlacesReturnType;
|
@ -0,0 +1,27 @@
|
|||||||
|
import PlacesModel from '../../../common/model/placesModel';
|
||||||
|
import IGetPlacesRepo from '../../data/repository/IGetPlacesRepo';
|
||||||
|
import { GetPlacesRO } from '../../data/response-object/protocols';
|
||||||
|
import GettingPlacesUsecase from '../getPlaceUsecase';
|
||||||
|
|
||||||
|
const mockedRO: GetPlacesRO = {
|
||||||
|
availableServices: [''],
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
id: 'id',
|
||||||
|
name: 'name',
|
||||||
|
parentId: null,
|
||||||
|
placeType: 'continent',
|
||||||
|
updatedAt: 'updatedTime',
|
||||||
|
qr: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const model = new PlacesModel(mockedRO);
|
||||||
|
const mockedRepo: IGetPlacesRepo = jest.fn().mockImplementation(async () => model);
|
||||||
|
|
||||||
|
describe('getting places usecase tests', () => {
|
||||||
|
it('call repository on execute usecase', async () => {
|
||||||
|
const usecase = new GettingPlacesUsecase(mockedRepo);
|
||||||
|
await usecase.execute();
|
||||||
|
|
||||||
|
expect(mockedRepo).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,21 @@
|
|||||||
|
import PlacesModel from '../../common/model/placesModel';
|
||||||
|
import IGetPlacesRepo from '../data/repository/IGetPlacesRepo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this usecase is responsible for calling the repo and returning the places data from the repository
|
||||||
|
*/
|
||||||
|
class GettingPlacesUsecase {
|
||||||
|
private repository: IGetPlacesRepo;
|
||||||
|
|
||||||
|
constructor(repository: IGetPlacesRepo) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(): Promise<PlacesModel> {
|
||||||
|
// call usecase and return the repo
|
||||||
|
const placesData = await this.repository();
|
||||||
|
return placesData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GettingPlacesUsecase;
|
@ -0,0 +1,26 @@
|
|||||||
|
import Users from '../../entity/entity';
|
||||||
|
|
||||||
|
class UsersModel {
|
||||||
|
private usersList: Users[];
|
||||||
|
|
||||||
|
private modelTitle = 'users';
|
||||||
|
|
||||||
|
constructor(data: Users[]) {
|
||||||
|
this.usersList = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): Users[] {
|
||||||
|
return this.usersList;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitle(): string {
|
||||||
|
return this.modelTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
addUser(user: Users): Users[] {
|
||||||
|
this.usersList.push(user);
|
||||||
|
return this.usersList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UsersModel;
|
6
src/business-logic/core/users/common/entity/entity.ts
Normal file
6
src/business-logic/core/users/common/entity/entity.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default interface Users {
|
||||||
|
profileId: string;
|
||||||
|
firstname: string;
|
||||||
|
lastname: string;
|
||||||
|
accountId: string;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { CreateAccountDTOReturnType, INewUserData } from './protocols';
|
||||||
|
|
||||||
|
const createAccountDTO = (newUser: INewUserData): CreateAccountDTOReturnType => ({
|
||||||
|
enabled: true,
|
||||||
|
firstName: newUser.firstname,
|
||||||
|
lastName: newUser.lastname,
|
||||||
|
username: newUser.phonenumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createAccountDTO;
|
@ -0,0 +1,12 @@
|
|||||||
|
export interface INewUserData {
|
||||||
|
firstname: string;
|
||||||
|
lastname: string;
|
||||||
|
phonenumber: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateAccountDTOReturnType = {
|
||||||
|
username: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
enabled: true;
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
import { INewUserData } from '../dto/protocols';
|
||||||
|
import { CreateAccountROReturnType } from '../response-object/protocols';
|
||||||
|
|
||||||
|
interface ICreateAcountRepo {
|
||||||
|
execute: (newUser: INewUserData) => Promise<CreateAccountROReturnType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ICreateAcountRepo;
|
@ -0,0 +1,24 @@
|
|||||||
|
import createAccountDTO from '../dto/createAccountDTO';
|
||||||
|
import { INewUserData } from '../dto/protocols';
|
||||||
|
import createAcountRO from '../response-object/createAcountRO';
|
||||||
|
import { CreateAccountROReturnType } from '../response-object/protocols';
|
||||||
|
import ICreateAcountRepo from './ICreateAcountRepo';
|
||||||
|
import { HttpHandler } from './protocols';
|
||||||
|
|
||||||
|
export default class CreateAccountRepo implements ICreateAcountRepo {
|
||||||
|
private httpHandler: HttpHandler;
|
||||||
|
|
||||||
|
constructor(httpHandler: HttpHandler) {
|
||||||
|
this.httpHandler = httpHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute: (newUser: INewUserData) => Promise<CreateAccountROReturnType> = async (newUser: INewUserData) => {
|
||||||
|
// call dto
|
||||||
|
const dto = createAccountDTO(newUser);
|
||||||
|
// call
|
||||||
|
const newAccountResponse = await this.httpHandler(dto);
|
||||||
|
// call response object
|
||||||
|
const newAccount = createAcountRO(newAccountResponse);
|
||||||
|
return newAccount;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
import { INewUserData } from '../dto/protocols';
|
||||||
|
import { CreateAcountResponseApi } from '../response-object/protocols';
|
||||||
|
|
||||||
|
export type HttpHandler = (newUser: INewUserData) => Promise<CreateAcountResponseApi>;
|
@ -0,0 +1,8 @@
|
|||||||
|
import { CreateAccountROReturnType, CreateAcountResponseApi } from './protocols';
|
||||||
|
|
||||||
|
const createAcountRO = (apiResponse: CreateAcountResponseApi): CreateAccountROReturnType => ({
|
||||||
|
accountId: apiResponse.id,
|
||||||
|
phonenumber: apiResponse.username,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createAcountRO;
|
@ -0,0 +1,10 @@
|
|||||||
|
export type CreateAcountResponseApi = {
|
||||||
|
nextRequestTimestamp: number;
|
||||||
|
username: string;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateAccountROReturnType = {
|
||||||
|
phonenumber: string;
|
||||||
|
accountId: string;
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
import { CreateProfileDtoType, ICreateNewProfileData } from './protocols';
|
||||||
|
|
||||||
|
const createProfileDTO: CreateProfileDtoType = (userAccount: ICreateNewProfileData) => ({
|
||||||
|
account_id: userAccount.accountId,
|
||||||
|
first_name: userAccount.firstname,
|
||||||
|
last_name: userAccount.lastname,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createProfileDTO;
|
@ -0,0 +1,12 @@
|
|||||||
|
import { INewUserData } from '../../../create-account/data/dto/protocols';
|
||||||
|
import { CreateAccountROReturnType } from '../../../create-account/data/response-object/protocols';
|
||||||
|
|
||||||
|
export type ICreateNewProfileData = CreateAccountROReturnType & INewUserData;
|
||||||
|
|
||||||
|
export type CreateProfileDtoReturnType = {
|
||||||
|
account_id: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateProfileDtoType = (userAccount: ICreateNewProfileData) => CreateProfileDtoReturnType;
|
@ -0,0 +1,22 @@
|
|||||||
|
/* eslint-disable no-useless-constructor */
|
||||||
|
import RepositoryHandler from '~/driven/utils/helpers/repository-handler/repositoryHandler';
|
||||||
|
import { CreateProfileDtoReturnType, ICreateNewProfileData } from '../dto/protocols';
|
||||||
|
import createProfileDTO from '../dto/createProfileDTO';
|
||||||
|
import ICreateProfileRepo from './ICreateProfileRepo';
|
||||||
|
import { HttpHandler } from './protocols';
|
||||||
|
|
||||||
|
export default class CreateProfileRepo
|
||||||
|
extends RepositoryHandler<CreateProfileDtoReturnType, string>
|
||||||
|
implements ICreateProfileRepo
|
||||||
|
{
|
||||||
|
constructor(httpHandler: HttpHandler) {
|
||||||
|
super(httpHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(accountData: ICreateNewProfileData) {
|
||||||
|
// create data in dto
|
||||||
|
const dto = createProfileDTO(accountData);
|
||||||
|
// call main http handler
|
||||||
|
return await this.httpHandler(dto);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import { ICreateNewProfileData } from '../dto/protocols';
|
||||||
|
|
||||||
|
export default interface ICreateProfileRepo {
|
||||||
|
execute: (accountData: ICreateNewProfileData) => Promise<string>;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import { CreateProfileDtoReturnType } from '../dto/protocols';
|
||||||
|
|
||||||
|
export type HttpHandler = (newUser: CreateProfileDtoReturnType) => Promise<string>;
|
3
src/business-logic/core/users/create-user/index.ts
Normal file
3
src/business-logic/core/users/create-user/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import CreateUserInfra from './infra/createUserInfra';
|
||||||
|
|
||||||
|
export default CreateUserInfra;
|
@ -0,0 +1,29 @@
|
|||||||
|
import CreateAccountRepo from '../create-account/data/repository/createAcountRepo';
|
||||||
|
import { HttpHandler as HttpAccountHandler } from '../create-account/data/repository/protocols';
|
||||||
|
import CreateProfileRepo from '../create-profile/data/repository/CreateRepositoryRepo';
|
||||||
|
import { HttpHandler as HttpProfileHandler } from '../create-profile/data/repository/protocols';
|
||||||
|
import CreateUserUsecase from '../usecase/createUserUsecase';
|
||||||
|
|
||||||
|
class CreateUserInfra {
|
||||||
|
private httpAccountHandler: HttpAccountHandler;
|
||||||
|
|
||||||
|
private httpProfileHandler: HttpProfileHandler;
|
||||||
|
|
||||||
|
constructor(httpAccountHandler: HttpAccountHandler, httpProfileHandler: HttpProfileHandler) {
|
||||||
|
this.httpAccountHandler = httpAccountHandler;
|
||||||
|
this.httpProfileHandler = httpProfileHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
// make account repositroy ready
|
||||||
|
const accountRepository = new CreateAccountRepo(this.httpAccountHandler);
|
||||||
|
// make profile repository ready
|
||||||
|
const profileRepository = new CreateProfileRepo(this.httpProfileHandler);
|
||||||
|
// make usecase ready
|
||||||
|
const usecase = new CreateUserUsecase(accountRepository, profileRepository);
|
||||||
|
// return prepared method to call and create user
|
||||||
|
return usecase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateUserInfra;
|
10
src/business-logic/core/users/create-user/ports.ts
Normal file
10
src/business-logic/core/users/create-user/ports.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { HttpHandler as HttpProfileHandler } from './create-profile/data/repository/protocols';
|
||||||
|
import { HttpHandler as HttpAccountHandler } from './create-account/data/repository/protocols';
|
||||||
|
import CreateUserUsecase from './usecase/createUserUsecase';
|
||||||
|
|
||||||
|
export default interface createUserPort {
|
||||||
|
httpAccountHandler: HttpAccountHandler;
|
||||||
|
httpProfileHandler: HttpProfileHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type createUserReturnType = CreateUserUsecase;
|
@ -0,0 +1,27 @@
|
|||||||
|
import { INewUserData } from '../create-account/data/dto/protocols';
|
||||||
|
import ICreateAcountRepo from '../create-account/data/repository/ICreateAcountRepo';
|
||||||
|
import ICreateProfileRepo from '../create-profile/data/repository/ICreateProfileRepo';
|
||||||
|
|
||||||
|
export default class CreateUserUsecase {
|
||||||
|
private accountRepository: ICreateAcountRepo;
|
||||||
|
|
||||||
|
private profileRepository: ICreateProfileRepo;
|
||||||
|
|
||||||
|
constructor(accountRepository: ICreateAcountRepo, profileRepository: ICreateProfileRepo) {
|
||||||
|
this.accountRepository = accountRepository;
|
||||||
|
this.profileRepository = profileRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(newUser: INewUserData) {
|
||||||
|
// create acount
|
||||||
|
const newAccountResponse = await this.accountRepository.execute(newUser);
|
||||||
|
const newProfileData = {
|
||||||
|
...newAccountResponse,
|
||||||
|
...newUser,
|
||||||
|
};
|
||||||
|
// create profile by account ID
|
||||||
|
const newProfileResponse = await this.profileRepository.execute(newProfileData);
|
||||||
|
|
||||||
|
return newProfileResponse;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import UsersModel from '../../../common/data/model/usersModel';
|
||||||
|
|
||||||
|
type IGetUsersRepo = () => Promise<UsersModel>;
|
||||||
|
|
||||||
|
export default IGetUsersRepo;
|
@ -0,0 +1,16 @@
|
|||||||
|
import UsersModel from '../../../common/data/model/usersModel';
|
||||||
|
import getUsersResponseObject from '../response-object/usersRO';
|
||||||
|
import { GetUsersResponse } from '../response-object/protocols';
|
||||||
|
|
||||||
|
const getUsersRepo = async (httpHandler: () => Promise<GetUsersResponse>) => {
|
||||||
|
// call httpHandler
|
||||||
|
const usersResponse = await httpHandler();
|
||||||
|
// user response object to turn it to the data that we want
|
||||||
|
const usersData = getUsersResponseObject(usersResponse);
|
||||||
|
// make model
|
||||||
|
const usersModel = new UsersModel(usersData);
|
||||||
|
// return the model
|
||||||
|
return usersModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getUsersRepo;
|
@ -0,0 +1,18 @@
|
|||||||
|
export type GetUsersResponse = {
|
||||||
|
_id: string;
|
||||||
|
account_type: string;
|
||||||
|
updated_at: string;
|
||||||
|
created_at: string;
|
||||||
|
subscription_method: string;
|
||||||
|
last_login_method: string;
|
||||||
|
account_number: null | number;
|
||||||
|
balance: number;
|
||||||
|
account_id: string;
|
||||||
|
user_data: {
|
||||||
|
_id: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
avatar: string;
|
||||||
|
};
|
||||||
|
__v: number;
|
||||||
|
}[];
|
@ -0,0 +1,16 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
import Users from '../../../common/entity/entity';
|
||||||
|
import { GetUsersResponse } from './protocols';
|
||||||
|
|
||||||
|
const getUsersResponseObject = (apiResponse: GetUsersResponse): Users[] => {
|
||||||
|
return apiResponse.map((userItem) => {
|
||||||
|
return {
|
||||||
|
profileId: userItem._id,
|
||||||
|
firstname: userItem.user_data.first_name,
|
||||||
|
lastname: userItem.user_data.last_name,
|
||||||
|
accountId: userItem.account_id,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getUsersResponseObject;
|
3
src/business-logic/core/users/get-users/index.ts
Normal file
3
src/business-logic/core/users/get-users/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import getUsers from './infra/getUsersInfra';
|
||||||
|
|
||||||
|
export default getUsers;
|
@ -0,0 +1,15 @@
|
|||||||
|
import IGetUsersRepo from '../data/repository/IGetUserRepo';
|
||||||
|
import getUsersRepo from '../data/repository/getUserRepo';
|
||||||
|
import GettingUsersUsecase from '../usecase/getUsersUsecase';
|
||||||
|
import { IgetusersInfra, getusersReturnType } from './protocols';
|
||||||
|
|
||||||
|
const getUsers = ({ httpHandler }: IgetusersInfra): getusersReturnType => {
|
||||||
|
// get httpHandler
|
||||||
|
const repository: IGetUsersRepo = () => getUsersRepo(httpHandler);
|
||||||
|
// connet usecase and repository
|
||||||
|
const usecase = new GettingUsersUsecase(repository);
|
||||||
|
// return method to use
|
||||||
|
return () => usecase.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getUsers;
|
@ -0,0 +1,8 @@
|
|||||||
|
import UsersModel from '../../common/data/model/usersModel';
|
||||||
|
import { GetUsersResponse } from '../data/response-object/protocols';
|
||||||
|
|
||||||
|
export interface IgetUsersInfra {
|
||||||
|
httpHandler: () => Promise<GetUsersResponse>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type getUsersReturnType = () => Promise<UsersModel>;
|
5
src/business-logic/core/users/get-users/ports.ts
Normal file
5
src/business-logic/core/users/get-users/ports.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { getUsersReturnType, type IgetUsersInfra } from './infra/protocols';
|
||||||
|
|
||||||
|
export default IgetUsersInfra;
|
||||||
|
|
||||||
|
export type getUsersReturnPort = getUsersReturnType;
|
@ -0,0 +1,21 @@
|
|||||||
|
import UsersModel from '../../common/data/model/usersModel';
|
||||||
|
import IGetUsersRepo from '../data/repository/IGetUserRepo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this usecase is responsible for calling the repo and returning the users data from the repository
|
||||||
|
*/
|
||||||
|
class GettingUsersUsecase {
|
||||||
|
private repository: IGetUsersRepo;
|
||||||
|
|
||||||
|
constructor(repository: IGetUsersRepo) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(): Promise<UsersModel> {
|
||||||
|
// call usecase and return the repo
|
||||||
|
const usersData = await this.repository();
|
||||||
|
return usersData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GettingUsersUsecase;
|
@ -0,0 +1,14 @@
|
|||||||
|
import { AdminOtpData } from '../../usecase/otpAuthUsecase';
|
||||||
|
|
||||||
|
export type OtpAuthDTOReturnType = {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
grant_type: 'otp';
|
||||||
|
};
|
||||||
|
const OtpAuthDTO = (dataToSend: AdminOtpData): OtpAuthDTOReturnType => ({
|
||||||
|
grant_type: 'otp',
|
||||||
|
password: dataToSend.otp,
|
||||||
|
username: dataToSend.phonenumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default OtpAuthDTO;
|
@ -0,0 +1,23 @@
|
|||||||
|
import AdminUser from '~/business-logic/generic/admin-user/common/entity/adminUserEntity';
|
||||||
|
|
||||||
|
export type OtpAuthResponse = {
|
||||||
|
access_token: string;
|
||||||
|
expires_in: number;
|
||||||
|
refresh_expires_in: number;
|
||||||
|
refresh_token: string;
|
||||||
|
token_type: 'Bearer';
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IOtpAuthRO extends OtpAuthResponse {
|
||||||
|
phonenumber: string;
|
||||||
|
}
|
||||||
|
const otpAuthRO = (response: IOtpAuthRO): AdminUser => ({
|
||||||
|
accessToken: response.access_token,
|
||||||
|
expiresIn: response.expires_in,
|
||||||
|
phonenumber: response.phonenumber,
|
||||||
|
refreshExpiresIn: response.refresh_expires_in,
|
||||||
|
refreshToken: response.refresh_token,
|
||||||
|
tokenType: response.token_type,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default otpAuthRO;
|
@ -0,0 +1,6 @@
|
|||||||
|
import AdminUserModel from '../../../../common/data/model/adminUserModel';
|
||||||
|
import { AdminOtpData } from '../../usecase/otpAuthUsecase';
|
||||||
|
|
||||||
|
export default interface IOtpAuthRepo {
|
||||||
|
execute(otpData: AdminOtpData): Promise<AdminUserModel>;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
import { AdminOtpData } from '../../usecase/otpAuthUsecase';
|
||||||
|
import otpAuthRO, { OtpAuthResponse } from '../reponse-object/otpAuthRO';
|
||||||
|
import OtpAuthDTO, { OtpAuthDTOReturnType } from '../dto/otpAuthDto';
|
||||||
|
import IOtpAuthRepo from './IOtpAuthRepo';
|
||||||
|
|
||||||
|
export type OtpHttpHandler = (data: OtpAuthDTOReturnType) => Promise<OtpAuthResponse>;
|
||||||
|
|
||||||
|
export default class OtpAuthRepo implements IOtpAuthRepo {
|
||||||
|
private httpHandler: OtpHttpHandler;
|
||||||
|
|
||||||
|
constructor(httpHandler: OtpHttpHandler) {
|
||||||
|
this.httpHandler = httpHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(otpData: AdminOtpData): Promise<AdminUserModel> {
|
||||||
|
// call dto
|
||||||
|
const dto = OtpAuthDTO(otpData);
|
||||||
|
// call handler
|
||||||
|
const response = await this.httpHandler(dto);
|
||||||
|
// call ro
|
||||||
|
const responseObjectData = {
|
||||||
|
...response,
|
||||||
|
phonenumber: otpData.phonenumber,
|
||||||
|
};
|
||||||
|
const responseObject = otpAuthRO(responseObjectData);
|
||||||
|
// make model
|
||||||
|
const adminModel = new AdminUserModel(responseObject);
|
||||||
|
// return model
|
||||||
|
return adminModel;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import otpAuthInfra from './infra/otpAuthInfra';
|
||||||
|
|
||||||
|
export default otpAuthInfra;
|
@ -0,0 +1,13 @@
|
|||||||
|
import OtpAuthRepo, { OtpHttpHandler } from '../data/repository/otpAuthRepo';
|
||||||
|
import OtpAuthUsecase from '../usecase/otpAuthUsecase';
|
||||||
|
|
||||||
|
const otpAuthInfra = (httpHandler: OtpHttpHandler) => {
|
||||||
|
// make the repo ready
|
||||||
|
const repository = new OtpAuthRepo(httpHandler);
|
||||||
|
// make the usecase ready
|
||||||
|
const usecase = new OtpAuthUsecase(repository);
|
||||||
|
// return method
|
||||||
|
return usecase;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default otpAuthInfra;
|
@ -0,0 +1,8 @@
|
|||||||
|
import { OtpHttpHandler } from './data/repository/otpAuthRepo';
|
||||||
|
import OtpAuthUsecase from './usecase/otpAuthUsecase';
|
||||||
|
|
||||||
|
export interface IOtpAuthDrivenPort {
|
||||||
|
httpHandler: OtpHttpHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OtpAuthDrivingPort = OtpAuthUsecase;
|
@ -0,0 +1,35 @@
|
|||||||
|
import AdminUserModel from '../../../common/data/model/adminUserModel';
|
||||||
|
import IOtpAuthRepo from '../data/repository/IOtpAuthRepo';
|
||||||
|
import OtpAuthUsecaseException from './otpException';
|
||||||
|
|
||||||
|
export type AdminOtpData = {
|
||||||
|
otp: string;
|
||||||
|
phonenumber: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IOtpAuthUsecase {
|
||||||
|
execute(data: AdminOtpData): Promise<AdminUserModel>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class OtpAuthUsecase implements IOtpAuthUsecase {
|
||||||
|
private repository: IOtpAuthRepo;
|
||||||
|
|
||||||
|
private validLenghtOfOtp = 6;
|
||||||
|
|
||||||
|
constructor(repository: IOtpAuthRepo) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(data: AdminOtpData): Promise<AdminUserModel> {
|
||||||
|
// check length of otp
|
||||||
|
const isOtpValid = this.isOtpValid(data.otp);
|
||||||
|
if (!isOtpValid) throw new OtpAuthUsecaseException();
|
||||||
|
// call the repo
|
||||||
|
const updatedAdminModal = await this.repository.execute(data);
|
||||||
|
return updatedAdminModal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isOtpValid(otp: string) {
|
||||||
|
return !!(otp.length >= this.validLenghtOfOtp);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export default class OtpAuthUsecaseException extends Error {}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { AdminData } from '../../usecase/phonenumberAuthUsecase';
|
||||||
|
|
||||||
|
export type PhonenumberAuthDTOReturnType = {
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
const phonenumberAuthDTO = (adminData: AdminData): PhonenumberAuthDTOReturnType => ({
|
||||||
|
username: adminData.phonenumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default phonenumberAuthDTO;
|
@ -0,0 +1,5 @@
|
|||||||
|
import { AdminData } from '../../usecase/phonenumberAuthUsecase';
|
||||||
|
|
||||||
|
export default interface IPhoneNumberAuthRepo {
|
||||||
|
execute(adminData: AdminData): Promise<string>;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import { AdminData } from '../../usecase/phonenumberAuthUsecase';
|
||||||
|
import phonenumberAuthDTO, { PhonenumberAuthDTOReturnType } from '../dto/phonenumberDto';
|
||||||
|
import IPhoneNumberAuthRepo from './IPhoneNumberAuthRepo';
|
||||||
|
|
||||||
|
export type RepoHttpHandler = (dtoData: PhonenumberAuthDTOReturnType) => Promise<string>;
|
||||||
|
export default class PhoneNumberAuthRepo implements IPhoneNumberAuthRepo {
|
||||||
|
private httpHandler: RepoHttpHandler;
|
||||||
|
|
||||||
|
constructor(httpHandler: RepoHttpHandler) {
|
||||||
|
this.httpHandler = httpHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(adminData: AdminData): Promise<string> {
|
||||||
|
// make dto
|
||||||
|
const data = phonenumberAuthDTO(adminData);
|
||||||
|
// call http handler
|
||||||
|
const response = await this.httpHandler(data);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import phonenumberAuthInfra from './infra/phonenumberAuthInfra';
|
||||||
|
|
||||||
|
export default phonenumberAuthInfra;
|
@ -0,0 +1,21 @@
|
|||||||
|
import PhoneNumberAuthRepo, { RepoHttpHandler } from '../data/repository/phonenumberAuthRepo';
|
||||||
|
import PhonenumberAuthUsecase from '../usecase/phonenumberAuthUsecase';
|
||||||
|
|
||||||
|
export interface IPhonenumberAuthInfra {
|
||||||
|
httpHandler: RepoHttpHandler;
|
||||||
|
wrongPhoneNumberMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const phonenumberAuthInfra = ({
|
||||||
|
httpHandler,
|
||||||
|
wrongPhoneNumberMessage,
|
||||||
|
}: IPhonenumberAuthInfra): PhonenumberAuthUsecase => {
|
||||||
|
// prepare repo
|
||||||
|
const repository = new PhoneNumberAuthRepo(httpHandler);
|
||||||
|
// prepare usecase
|
||||||
|
const usecase = new PhonenumberAuthUsecase(repository, wrongPhoneNumberMessage);
|
||||||
|
// return main method
|
||||||
|
return usecase;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default phonenumberAuthInfra;
|
@ -0,0 +1,5 @@
|
|||||||
|
import { IPhonenumberAuthInfra } from './infra/phonenumberAuthInfra';
|
||||||
|
import PhonenumberAuthUsecase from './usecase/phonenumberAuthUsecase';
|
||||||
|
|
||||||
|
export type IPhonenumberAuthPort = IPhonenumberAuthInfra;
|
||||||
|
export type PhonenumberReturnTypePort = Promise<PhonenumberAuthUsecase>;
|
@ -0,0 +1 @@
|
|||||||
|
export default class PhonenumberException extends Error {}
|
@ -0,0 +1,36 @@
|
|||||||
|
import IPhoneNumberAuthRepo from '../data/repository/IPhoneNumberAuthRepo';
|
||||||
|
import PhonenumberException from './exception';
|
||||||
|
|
||||||
|
export type AdminData = {
|
||||||
|
phonenumber: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IPhoneNumberAuthUsecase {
|
||||||
|
execute(adminData: AdminData): Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class PhonenumberAuthUsecase implements IPhoneNumberAuthUsecase {
|
||||||
|
private repository: IPhoneNumberAuthRepo;
|
||||||
|
|
||||||
|
private wrongPhoneNumberMessage: string;
|
||||||
|
|
||||||
|
constructor(repository: IPhoneNumberAuthRepo, wrongPhoneNumberMessage: string) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.wrongPhoneNumberMessage = wrongPhoneNumberMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(adminData: AdminData): Promise<string> {
|
||||||
|
// check phone number regex
|
||||||
|
const isPhoenumberValid = this.isPhoneNumberValid(adminData.phonenumber);
|
||||||
|
if (!isPhoenumberValid) throw new PhonenumberException(this.wrongPhoneNumberMessage);
|
||||||
|
|
||||||
|
const response = await this.repository.execute(adminData);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isPhoneNumberValid(phonenumber: string) {
|
||||||
|
const regex = /\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/;
|
||||||
|
return regex.test(phonenumber);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import AdminUser from '../../entity/adminUserEntity';
|
||||||
|
|
||||||
|
export default class AdminUserModel {
|
||||||
|
adminUserData: AdminUser;
|
||||||
|
|
||||||
|
constructor(adminUserData: AdminUser) {
|
||||||
|
this.adminUserData = adminUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return this.adminUserData;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
export default abstract class AdminUser {
|
||||||
|
abstract phonenumber: string;
|
||||||
|
|
||||||
|
abstract accessToken: string;
|
||||||
|
|
||||||
|
abstract refreshToken: string;
|
||||||
|
|
||||||
|
abstract expiresIn: number;
|
||||||
|
|
||||||
|
abstract refreshExpiresIn: number;
|
||||||
|
|
||||||
|
abstract tokenType: 'Bearer';
|
||||||
|
}
|
40
src/driven/adapters/auth-admin-login/authAdminLogin.ts
Normal file
40
src/driven/adapters/auth-admin-login/authAdminLogin.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import { IOtpAuthDrivenPort } from '~/business-logic/generic/admin-user/authentication/otp-auth/port';
|
||||||
|
import { OtpAuthResponse } from '~/business-logic/generic/admin-user/authentication/otp-auth/data/reponse-object/otpAuthRO';
|
||||||
|
import { OtpAuthDTOReturnType } from '~/business-logic/generic/admin-user/authentication/otp-auth/data/dto/otpAuthDto';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
|
||||||
|
const authAdminLogin = (
|
||||||
|
userAdmin: AdminUserModel | null,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): IOtpAuthDrivenPort => {
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin && userAdmin.adminUserData.accessToken && null,
|
||||||
|
refreshToken: userAdmin && userAdmin.adminUserData.refreshToken && null,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
const httpHandler = (data: OtpAuthDTOReturnType): Promise<OtpAuthResponse> => {
|
||||||
|
const url = apiUrls.generic.authLogin;
|
||||||
|
const options: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
return httpProvider.request<OtpAuthResponse>(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
httpHandler,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default authAdminLogin;
|
@ -0,0 +1,44 @@
|
|||||||
|
import { staticMessages } from '~/driven/utils/constants/staticMessages';
|
||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
import { PhonenumberAuthDTOReturnType } from '~/business-logic/generic/admin-user/authentication/phonnumber-auth/data/dto/phonenumberDto';
|
||||||
|
import { IPhonenumberAuthPort } from '~/business-logic/generic/admin-user/authentication/phonnumber-auth/port';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
|
||||||
|
const authAdminPhoneNumberDriven = (
|
||||||
|
userAdmin: AdminUserModel | null,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): IPhonenumberAuthPort => {
|
||||||
|
// make http handler ready for the phone number
|
||||||
|
const wrongPhoneNumberMessage = staticMessages.global.errors.phonenumber;
|
||||||
|
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin && userAdmin?.adminUserData.accessToken && null,
|
||||||
|
refreshToken: userAdmin && userAdmin?.adminUserData.refreshToken && null,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
const httpHandler = (data: PhonenumberAuthDTOReturnType) => {
|
||||||
|
const url = apiUrls.generic.authPhonenumber;
|
||||||
|
const options: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
return httpProvider.request<string>(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
httpHandler,
|
||||||
|
wrongPhoneNumberMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default authAdminPhoneNumberDriven;
|
@ -0,0 +1,42 @@
|
|||||||
|
import { INewUserData } from '~/business-logic/core/users/create-user/create-account/data/dto/protocols';
|
||||||
|
import { CreateAcountResponseApi } from '~/business-logic/core/users/create-user/create-account/data/response-object/protocols';
|
||||||
|
import createUserPort from '~/business-logic/core/users/create-user/ports';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
|
||||||
|
const createAccountAdapter = (
|
||||||
|
userAdmin: AdminUserModel,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): createUserPort['httpAccountHandler'] => {
|
||||||
|
// make url
|
||||||
|
const url = apiUrls.core.createUserAccount;
|
||||||
|
// call http provider
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin.adminUserData.accessToken,
|
||||||
|
refreshToken: userAdmin.adminUserData.refreshToken,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
|
||||||
|
const httpHandler = (newUserData: INewUserData) => {
|
||||||
|
// api options
|
||||||
|
const httpOptions: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
data: newUserData,
|
||||||
|
};
|
||||||
|
return httpProvider.request<CreateAcountResponseApi>(httpOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
return httpHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createAccountAdapter;
|
@ -0,0 +1,41 @@
|
|||||||
|
import { CreateProfileDtoReturnType } from '~/business-logic/core/users/create-user/create-profile/data/dto/protocols';
|
||||||
|
import createUserPort from '~/business-logic/core/users/create-user/ports';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
|
||||||
|
const createProfileAdapter = (
|
||||||
|
userAdmin: AdminUserModel,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): createUserPort['httpProfileHandler'] => {
|
||||||
|
// make url
|
||||||
|
const url = apiUrls.core.createUserProfile;
|
||||||
|
// call http provider
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin.adminUserData.accessToken,
|
||||||
|
refreshToken: userAdmin.adminUserData.refreshToken,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
|
||||||
|
const httpHandler = (newAccountData: CreateProfileDtoReturnType) => {
|
||||||
|
// api options
|
||||||
|
const httpOptions: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
data: newAccountData,
|
||||||
|
};
|
||||||
|
return httpProvider.request<string>(httpOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
return httpHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createProfileAdapter;
|
40
src/driven/adapters/get-places-adapter/getPlacesAdapter.ts
Normal file
40
src/driven/adapters/get-places-adapter/getPlacesAdapter.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { GetPlacesResponse } from '~/business-logic/core/places/get-places/data/response-object/protocols';
|
||||||
|
import IGetPlacesPort from '~/business-logic/core/places/get-places/port';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
import { getPlacesAdapterReturnType } from './protocols';
|
||||||
|
|
||||||
|
const getPlacesAdapter = (
|
||||||
|
userAdmin: AdminUserModel,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): IGetPlacesPort & getPlacesAdapterReturnType => {
|
||||||
|
// url of api
|
||||||
|
const url = apiUrls.core.getPlaces;
|
||||||
|
// make the options of request
|
||||||
|
const options: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
// make the httpHandler
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin.adminUserData.accessToken,
|
||||||
|
refreshToken: userAdmin.adminUserData.refreshToken,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
|
||||||
|
const httpHandler = async () => httpProvider.request<GetPlacesResponse>(options);
|
||||||
|
|
||||||
|
// return the method
|
||||||
|
return {
|
||||||
|
httpHandler,
|
||||||
|
url,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getPlacesAdapter;
|
3
src/driven/adapters/get-places-adapter/protocols.ts
Normal file
3
src/driven/adapters/get-places-adapter/protocols.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type getPlacesAdapterReturnType = {
|
||||||
|
url: string;
|
||||||
|
};
|
40
src/driven/adapters/get-users-adapter/getUsersAdapter.ts
Normal file
40
src/driven/adapters/get-users-adapter/getUsersAdapter.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
|
||||||
|
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
|
||||||
|
import { GetUsersResponse } from '~/business-logic/core/users/get-users/data/response-object/protocols';
|
||||||
|
import IGetUsersPort from '~/business-logic/core/users/get-users/ports';
|
||||||
|
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
|
||||||
|
import { getUsersAdapterReturnType } from './protocols';
|
||||||
|
|
||||||
|
const getUsersAdapter = (
|
||||||
|
userAdmin: AdminUserModel,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
): IGetUsersPort & getUsersAdapterReturnType => {
|
||||||
|
// url of api
|
||||||
|
const url = apiUrls.core.getUsers;
|
||||||
|
// make the options of request
|
||||||
|
const options: HttpOptionsType = {
|
||||||
|
url,
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
// make the httpHandler
|
||||||
|
const httpProvider = new HTTPPovider(
|
||||||
|
{
|
||||||
|
accessToken: userAdmin.adminUserData.accessToken,
|
||||||
|
refreshToken: userAdmin.adminUserData.refreshToken,
|
||||||
|
},
|
||||||
|
updateAccessToken,
|
||||||
|
navigateToAuth,
|
||||||
|
);
|
||||||
|
|
||||||
|
const httpHandler = async () => httpProvider.request<GetUsersResponse>(options);
|
||||||
|
|
||||||
|
// return the method
|
||||||
|
return {
|
||||||
|
httpHandler,
|
||||||
|
url,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getUsersAdapter;
|
3
src/driven/adapters/get-users-adapter/protocols.ts
Normal file
3
src/driven/adapters/get-users-adapter/protocols.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type getUsersAdapterReturnType = {
|
||||||
|
url: string;
|
||||||
|
};
|
@ -1,11 +1,88 @@
|
|||||||
import axios, { AxiosRequestConfig } from 'axios';
|
/* eslint-disable consistent-return */
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
import axios, { AxiosInstance } from 'axios';
|
||||||
import { staticMessages } from '~/driven/utils/constants/staticMessages';
|
import { staticMessages } from '~/driven/utils/constants/staticMessages';
|
||||||
|
import { ApiGlobalResponseObject } from '~/driven/utils/protocols/serviceProtocols';
|
||||||
|
import { apiUrls } from '~/driven/utils/configs/appConfig';
|
||||||
|
import { HttpOptionsType } from './protocols';
|
||||||
|
|
||||||
export class HTTPBoundary {
|
interface IUserTokens {
|
||||||
async request<R>(options: AxiosRequestConfig) {
|
accessToken: string | null | undefined;
|
||||||
const response = await axios<R>(options);
|
refreshToken: string | null | undefined;
|
||||||
|
}
|
||||||
|
export class HTTPPovider {
|
||||||
|
private userTokens: IUserTokens;
|
||||||
|
|
||||||
|
private updateAccessToken: (newAccessToken: string) => void;
|
||||||
|
|
||||||
|
private navigateToAuth: () => void;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
userTokens: IUserTokens,
|
||||||
|
updateAccessToken: (newAccessToken: string) => void,
|
||||||
|
navigateToAuth: () => void,
|
||||||
|
) {
|
||||||
|
this.userTokens = userTokens;
|
||||||
|
this.updateAccessToken = updateAccessToken;
|
||||||
|
this.navigateToAuth = navigateToAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initalizeAxiosInstance() {
|
||||||
|
const instance = axios.create();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRequestInterceptor() {
|
||||||
|
const axiosInstance = this.initalizeAxiosInstance();
|
||||||
|
axiosInstance.interceptors.request.use((config) => {
|
||||||
|
config.headers.Authorization = `Bearer ${this.userTokens.accessToken}`;
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
return axiosInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async request<R>(customOptions: HttpOptionsType) {
|
||||||
|
const axiosInstance = this.handleRequestInterceptor();
|
||||||
|
this.responseIncepter(axiosInstance);
|
||||||
|
|
||||||
|
const response = await axiosInstance<ApiGlobalResponseObject<R>>(customOptions);
|
||||||
if (!response) throw new Error(staticMessages.service.errors[500]);
|
if (!response) throw new Error(staticMessages.service.errors[500]);
|
||||||
|
|
||||||
return response.data;
|
return response.data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo should be handled in business logic
|
||||||
|
*/
|
||||||
|
private async refreshAccessToken() {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(apiUrls.generic.authRefresh, {
|
||||||
|
refresh_token: this.userTokens.refreshToken,
|
||||||
|
});
|
||||||
|
this.updateAccessToken(response.data.access_token as string);
|
||||||
|
return response.data.access_token;
|
||||||
|
} catch (err) {
|
||||||
|
this.navigateToAuth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private responseIncepter(axiosInstance: AxiosInstance) {
|
||||||
|
axiosInstance.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
const originalRequest = error.config;
|
||||||
|
|
||||||
|
if (error.response.status === 401 && error.response.message === 'Unauthorized') {
|
||||||
|
const newAccessToken = this.refreshAccessToken().then(() => {
|
||||||
|
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
|
||||||
|
return axios(originalRequest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
src/driven/boundaries/http-boundary/protocols.ts
Normal file
3
src/driven/boundaries/http-boundary/protocols.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
export type HttpOptionsType = AxiosRequestConfig;
|
@ -1,8 +0,0 @@
|
|||||||
import store from '../store/store';
|
|
||||||
import userSlice from '../slices/userSlice';
|
|
||||||
import { UserState } from '../slices/protocols/userSliceProtocols';
|
|
||||||
|
|
||||||
export const userAdapter = {
|
|
||||||
get: store.getState().user,
|
|
||||||
update: (user: UserState) => store.dispatch(userSlice.actions.update(user)),
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export { userAdapter } from './adapters/adapter';
|
|
@ -1,3 +0,0 @@
|
|||||||
import { UserModel } from '~/business-logic/generic/user/common/domain/model/userModel';
|
|
||||||
|
|
||||||
export type UserState = UserModel;
|
|
@ -1,19 +0,0 @@
|
|||||||
import { createSlice, SliceCaseReducers } from '@reduxjs/toolkit';
|
|
||||||
import { UserState } from './protocols/userSliceProtocols';
|
|
||||||
|
|
||||||
export const userStateName = 'user';
|
|
||||||
const userSlice = createSlice<UserState, SliceCaseReducers<UserState>>({
|
|
||||||
name: userStateName,
|
|
||||||
initialState: null,
|
|
||||||
reducers: {
|
|
||||||
update: (state, action) => {
|
|
||||||
if (!action.payload) return state;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...action.payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default userSlice;
|
|
@ -1,12 +0,0 @@
|
|||||||
import { combineReducers, configureStore } from '@reduxjs/toolkit';
|
|
||||||
import userSlice, { userStateName } from '../slices/userSlice';
|
|
||||||
|
|
||||||
const combinedReducers = combineReducers({
|
|
||||||
[userStateName]: userSlice.reducer,
|
|
||||||
});
|
|
||||||
|
|
||||||
const store = configureStore({
|
|
||||||
reducer: combinedReducers,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default store;
|
|
3
src/driven/boundaries/state-management/index.ts
Normal file
3
src/driven/boundaries/state-management/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import StateManagementService from './stateManagementService';
|
||||||
|
|
||||||
|
export default StateManagementService;
|
@ -0,0 +1,6 @@
|
|||||||
|
export default abstract class StateManagementProvider {
|
||||||
|
abstract useGetQuery<DataType>(
|
||||||
|
key: string,
|
||||||
|
httpHandler: () => Promise<DataType>,
|
||||||
|
): { data: DataType | undefined; isLoading: boolean; error?: string };
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import StateManagementProvider from './stateManagementProvider';
|
||||||
|
import SwrBoundary from './swrBoundary';
|
||||||
|
|
||||||
|
export default class StateManagementService implements StateManagementProvider {
|
||||||
|
private provider: StateManagementProvider;
|
||||||
|
|
||||||
|
constructor(provider: StateManagementProvider) {
|
||||||
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
static swr() {
|
||||||
|
const stateManagement = new StateManagementService(new SwrBoundary());
|
||||||
|
return stateManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
useGetQuery<DataType>(
|
||||||
|
key: string,
|
||||||
|
httpHandler: () => Promise<DataType>,
|
||||||
|
): {
|
||||||
|
data: DataType | undefined;
|
||||||
|
isLoading: boolean;
|
||||||
|
error?: string | undefined;
|
||||||
|
} {
|
||||||
|
return this.provider.useGetQuery(key, httpHandler);
|
||||||
|
}
|
||||||
|
}
|
15
src/driven/boundaries/state-management/swrBoundary.ts
Normal file
15
src/driven/boundaries/state-management/swrBoundary.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import useSwr from 'swr';
|
||||||
|
import StateManagementProvider from './stateManagementProvider';
|
||||||
|
|
||||||
|
export default class SwrBoundary implements StateManagementProvider {
|
||||||
|
useGetQuery<DataType>(
|
||||||
|
key: string,
|
||||||
|
httpHandler: () => Promise<DataType>,
|
||||||
|
): {
|
||||||
|
data: DataType | undefined;
|
||||||
|
isLoading: boolean;
|
||||||
|
error?: string | undefined;
|
||||||
|
} {
|
||||||
|
return useSwr(key, httpHandler);
|
||||||
|
}
|
||||||
|
}
|
3
src/driven/boundaries/storage-boundary/index.ts
Normal file
3
src/driven/boundaries/storage-boundary/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import StorageService from './storageService';
|
||||||
|
|
||||||
|
export default StorageService;
|
@ -0,0 +1,18 @@
|
|||||||
|
import StorageProvider from './storageProvider';
|
||||||
|
|
||||||
|
export default class LocalStorageProvider<ValueType> implements StorageProvider<ValueType> {
|
||||||
|
setData(key: string, value: ValueType): void {
|
||||||
|
const jsonValue = JSON.stringify(value);
|
||||||
|
localStorage.setItem(key, jsonValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(key: string): ValueType | null {
|
||||||
|
const jsonValue = localStorage.getItem(key);
|
||||||
|
const value: ValueType = jsonValue && JSON.parse(jsonValue);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteData(key: string): void {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
export default abstract class StorageProvider<ValueType> {
|
||||||
|
abstract setData(key: string, value: ValueType): void;
|
||||||
|
|
||||||
|
abstract getData(key: string): ValueType | null;
|
||||||
|
|
||||||
|
abstract deleteData(key: string): void;
|
||||||
|
}
|
27
src/driven/boundaries/storage-boundary/storageService.ts
Normal file
27
src/driven/boundaries/storage-boundary/storageService.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import LocalStorageProvider from './localStorageProvider';
|
||||||
|
import StorageProvider from './storageProvider';
|
||||||
|
|
||||||
|
export default class StorageService<ValueType> implements StorageProvider<ValueType> {
|
||||||
|
private provider: StorageProvider<ValueType>;
|
||||||
|
|
||||||
|
constructor(provider: StorageProvider<ValueType>) {
|
||||||
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
static localStorage<ValuType>(): StorageService<ValuType> {
|
||||||
|
const localStorageService = new StorageService<ValuType>(new LocalStorageProvider<ValuType>());
|
||||||
|
return localStorageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(key: string, value: ValueType): void {
|
||||||
|
return this.provider.setData(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(key: string): ValueType | null {
|
||||||
|
return this.provider.getData(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteData(key: string): void {
|
||||||
|
this.provider.deleteData(key);
|
||||||
|
}
|
||||||
|
}
|
40
src/driven/utils/components/Notification/Notification.tsx
Normal file
40
src/driven/utils/components/Notification/Notification.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
export interface notifInterface {
|
||||||
|
type: 'error' | 'success' | 'warning';
|
||||||
|
message: string;
|
||||||
|
time?: number;
|
||||||
|
onCloseCallback?: () => unknown;
|
||||||
|
}
|
||||||
|
export default function Notification({ message, type, time = 5, onCloseCallback }: notifInterface) {
|
||||||
|
const notifRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const el = React.useRef(document.createElement('div'));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const portal = document.getElementById('root');
|
||||||
|
portal?.appendChild(el.current);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
el.current.remove();
|
||||||
|
if (typeof onCloseCallback !== 'undefined') onCloseCallback();
|
||||||
|
}, 1000 * time);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (typeof onCloseCallback !== 'undefined') onCloseCallback();
|
||||||
|
return el.current?.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return ReactDOM.createPortal(
|
||||||
|
<div
|
||||||
|
ref={notifRef}
|
||||||
|
className={`fixed top-10 left-1/2 translate-x-[-50%] z-30 p-2 rounded-md text-black ${
|
||||||
|
type === 'error' && 'bg-red-600 text-white'
|
||||||
|
} ${type === 'success' && 'bg-green-600 text-white'} ${type === 'warning' && 'bg-yellow-500'}`}
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</div>,
|
||||||
|
el.current,
|
||||||
|
);
|
||||||
|
}
|
@ -1,14 +1,21 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
|
||||||
interface IPrimaryButtonProps {
|
interface IPrimaryButtonProps {
|
||||||
title: string;
|
title: string;
|
||||||
onClick: (e: React.MouseEvent) => void;
|
onClick: (e: React.MouseEvent) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PrimaryButton(props: IPrimaryButtonProps) {
|
export default function PrimaryButton(props: IPrimaryButtonProps) {
|
||||||
const { onClick, title, className } = props;
|
const { onClick, title, className, isDisabled = false } = props;
|
||||||
return (
|
return (
|
||||||
<button onClick={onClick} className={`py-1 px-5 transition-all hover:bg-primary-300 bg-primary-main rounded-lg text-white text-center ${className}`}>{ title }</button>
|
<button
|
||||||
)
|
disabled={isDisabled}
|
||||||
|
onClick={onClick}
|
||||||
|
className={`py-1 px-5 transition-all hover:bg-primary-300 bg-primary-main rounded-lg text-white text-center ${className}`}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,41 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
|
||||||
interface ISimpleInput {
|
export type SetStateInputMethod<NameType> = (name: NameType, newValue: string) => void;
|
||||||
title: string;
|
|
||||||
|
interface ISimpleInput<NameType> {
|
||||||
|
inputData: {
|
||||||
|
title: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
className?: string;
|
className?: string;
|
||||||
|
stateHanlder: {
|
||||||
|
state: string;
|
||||||
|
setState: SetStateInputMethod<NameType>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SimpleInput(props: ISimpleInput) {
|
export default function SimpleInput<NameType>(props: ISimpleInput<NameType>) {
|
||||||
const { title, className } = props;
|
const { className, inputData, stateHanlder } = props;
|
||||||
|
const { name, title } = inputData;
|
||||||
|
const { setState, state } = stateHanlder;
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const { value, name: inputName } = e.target;
|
||||||
|
setState(inputName as NameType, value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-col ${className}`}>
|
<div className={`flex flex-col ${className}`}>
|
||||||
<label className='mb-1 text-txt-second text-xs' htmlFor={title}>{ title }</label>
|
<label className='mb-1 text-txt-second text-xs' htmlFor={title}>
|
||||||
<input className='bg-bg-gray h-11 rounded-lg focus:outline-0 px-2 text-txt-medium' id={title} />
|
{title}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
value={state}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
name={name}
|
||||||
|
className='bg-bg-gray h-11 rounded-lg focus:outline-0 px-2 text-txt-medium w-full'
|
||||||
|
id={title}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
13
src/driven/utils/components/loading/Loading.tsx
Normal file
13
src/driven/utils/components/loading/Loading.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import style from './style.module.css';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className={style.ldsRing}>
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
35
src/driven/utils/components/loading/style.module.css
Normal file
35
src/driven/utils/components/loading/style.module.css
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.ldsRing {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.ldsRing div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
margin: 4px;
|
||||||
|
border: 4px solid #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: ldsRing 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||||
|
border-color: var(--color-primary-main) transparent transparent transparent;
|
||||||
|
}
|
||||||
|
.ldsRing div:nth-child(1) {
|
||||||
|
animation-delay: -0.45s;
|
||||||
|
}
|
||||||
|
.ldsRing div:nth-child(2) {
|
||||||
|
animation-delay: -0.3s;
|
||||||
|
}
|
||||||
|
.ldsRing div:nth-child(3) {
|
||||||
|
animation-delay: -0.15s;
|
||||||
|
}
|
||||||
|
@keyframes ldsRing {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
|
||||||
interface IPageTitleProps {
|
interface IPageTitleProps {
|
||||||
title: string;
|
title: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PageTitle(props: IPageTitleProps) {
|
export default function PageTitle(props: IPageTitleProps) {
|
||||||
const { title, className } = props;
|
const { title, className } = props;
|
||||||
return (
|
return <div className={`w-full shadow-sm shadow-txt-light font-semibold ${className}`}>{title}</div>;
|
||||||
<div className={`w-full shadow-sm shadow-txt-light font-semibold ${className}`}>{title}</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,42 @@
|
|||||||
import { icons } from "../constants/assertUrls";
|
import { icons } from '../constants/assertUrls';
|
||||||
import { staticMessages } from "../constants/staticMessages";
|
import { ENVs } from '../constants/envs';
|
||||||
|
import { staticMessages } from '../constants/staticMessages';
|
||||||
|
|
||||||
export const appConfig = {};
|
export const appConfig = {
|
||||||
|
adminUserStorageKey: 'adminUser',
|
||||||
|
};
|
||||||
|
|
||||||
export const routes = {
|
export const routes = {
|
||||||
usersList: '/',
|
usersList: '/',
|
||||||
createUser: '/create-user'
|
createUser: '/create-user',
|
||||||
|
authentication: '/auth',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const routesData = {
|
export const routesData = {
|
||||||
usersList: {
|
usersList: {
|
||||||
path: routes.usersList,
|
path: routes.usersList,
|
||||||
icon: icons.users,
|
icon: icons.users,
|
||||||
title: staticMessages.global.users
|
title: staticMessages.global.users,
|
||||||
},
|
},
|
||||||
createUser: {
|
createUser: {
|
||||||
path: routes.createUser,
|
path: routes.createUser,
|
||||||
icon: icons.createUser,
|
icon: icons.createUser,
|
||||||
title: staticMessages.global.createUser
|
title: staticMessages.global.createUser,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const baseApiUrl = import.meta.env.BASE_API_URL;
|
const baseApiUrl = ENVs.apiOrigin;
|
||||||
export const apiUrls = {
|
export const apiUrls = {
|
||||||
|
core: {
|
||||||
|
getPlaces: `${baseApiUrl}${ENVs.apiGetPlaces}`,
|
||||||
|
getUsers: `${baseApiUrl}${ENVs.apiGetUsers}`,
|
||||||
|
createUserAccount: `${baseApiUrl}${ENVs.apiCreateUserAccount}`,
|
||||||
|
createUserProfile: `${baseApiUrl}${ENVs.apiCreateUserProfile}`,
|
||||||
|
createMember: `${baseApiUrl}${ENVs.apiCreateMember}`,
|
||||||
|
},
|
||||||
|
generic: {
|
||||||
|
authPhonenumber: `${ENVs.apiAuthOrigin}${ENVs.apiAuthPhonenumber}`,
|
||||||
|
authLogin: `${ENVs.apiAuthOrigin}${ENVs.apiAuthLogin}`,
|
||||||
|
authRefresh: `${ENVs.apiAuthOrigin}${ENVs.apiAuthRefresh}`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
const baseAssetsUrl = 'assets/';
|
const baseAssetsUrl = 'assets/';
|
||||||
const baseIconsUrl = baseAssetsUrl + 'icons/';
|
const baseIconsUrl = `${baseAssetsUrl}icons/`;
|
||||||
export const icons = {
|
export const icons = {
|
||||||
logo: baseIconsUrl + 'logo.svg',
|
logo: `${baseIconsUrl}logo.svg`,
|
||||||
users: baseIconsUrl + 'users.svg',
|
logoBlack: `${baseIconsUrl}logo-black.svg`,
|
||||||
createUser: baseIconsUrl + 'createuser.svg'
|
users: `${baseIconsUrl}users.svg`,
|
||||||
}
|
createUser: `${baseIconsUrl}createuser.svg`,
|
||||||
|
};
|
||||||
|
12
src/driven/utils/constants/envs.ts
Normal file
12
src/driven/utils/constants/envs.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const ENVs = {
|
||||||
|
apiOrigin: process.env.VITE_API_ORIGIN,
|
||||||
|
apiAuthOrigin: process.env.VITE_API_AUTH_ORIGIN,
|
||||||
|
apiAuthPhonenumber: process.env.VITE_API_AUTH_PHONENUMBER,
|
||||||
|
apiAuthLogin: process.env.VITE_API_AUTH_LOGIN,
|
||||||
|
apiAuthRefresh: process.env.VITE_API_AUTH_REFRESH,
|
||||||
|
apiGetPlaces: process.env.VITE_API_PLACES,
|
||||||
|
apiGetUsers: process.env.VITE_API_USERS,
|
||||||
|
apiCreateUserAccount: process.env.VITE_API_USERS_ACCOUNT,
|
||||||
|
apiCreateUserProfile: process.env.VITE_API_USERS_PROFILE,
|
||||||
|
apiCreateMember: process.env.VITE_API_CREATE_MEMBER,
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user