TP-24538: Initial commit for the base setup for the houston-ui
This commit is contained in:
28
.eslintignore
Normal file
28
.eslintignore
Normal file
@@ -0,0 +1,28 @@
|
||||
dist/*
|
||||
src/model/offer-management
|
||||
|
||||
*.iml
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
#IDE
|
||||
.idea/
|
||||
|
||||
# Configuration
|
||||
config.js
|
||||
config.qa.js
|
||||
setup.template.js
|
||||
|
||||
80
.eslintrc.json
Normal file
80
.eslintrc.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
"jest": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["react", "@typescript-eslint", "react-hooks", "prettier", "import"],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"]
|
||||
},
|
||||
"typescript": {}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"react/no-array-index-key": "warn",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"no-console": "warn",
|
||||
"@typescript-eslint/member-delimiter-style": "warn",
|
||||
"@typescript-eslint/ban-types": "warn",
|
||||
"@typescript-eslint/type-annotation-spacing": "warn",
|
||||
"@typescript-eslint/no-inferrable-types": "warn",
|
||||
"@typescript-eslint/no-empty-interface": "warn",
|
||||
"@typescript-eslint/no-empty-function": "warn",
|
||||
"@typescript-eslint/no-var-requires": "warn",
|
||||
"import/extension": "off",
|
||||
"react/jsx-filename-extension": [1, { "extensions": [".ts", ".tsx"] }],
|
||||
"no-shadow": "off",
|
||||
"import/prefer-default-export": "off",
|
||||
"react/jsx-props-no-spreading": "off",
|
||||
"react/destructuring-assignment": "warn",
|
||||
"jsx-a11y/control-has-associated-label": "off",
|
||||
"no-unused-vars": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"max-classes-per-file": "off",
|
||||
"react/no-unused-prop-types": "warn",
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/jsx-no-bind": "warn",
|
||||
"react/default-props-match-prop-types": "warn",
|
||||
"react/prop-types": "warn",
|
||||
"import/no-named-default": "off",
|
||||
"react/require-default-props": "off",
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"js": "never",
|
||||
"jsx": "never",
|
||||
"ts": "never",
|
||||
"tsx": "never"
|
||||
}
|
||||
],
|
||||
"react/function-component-definition": [
|
||||
2,
|
||||
{
|
||||
"namedComponents": "arrow-function",
|
||||
"unnamedComponents": "arrow-function"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
node_modules
|
||||
|
||||
.npmrc
|
||||
|
||||
dist
|
||||
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
**/.DS_Store
|
||||
|
||||
# configuration files
|
||||
config.js
|
||||
config.qa.js
|
||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
build/
|
||||
node_modules/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
10
.prettierrc
Normal file
10
.prettierrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "avoid",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
36
Dockerfile
Normal file
36
Dockerfile
Normal file
@@ -0,0 +1,36 @@
|
||||
FROM 193044292705.dkr.ecr.ap-south-1.amazonaws.com/common/node:16.15.1-alpine3.16 as build
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
RUN yarn install
|
||||
RUN yarn prettier-check
|
||||
RUN yarn eslint-check
|
||||
RUN yarn build
|
||||
|
||||
FROM 193044292705.dkr.ecr.ap-south-1.amazonaws.com/common/nginx:1.23.3-alpine
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
RUN adduser -u 4000 non-root-user -D ''
|
||||
RUN chown -R 4000:4000 /var/cache/nginx \
|
||||
&& chown -R 4000:4000 /etc/nginx/conf.d/ \
|
||||
&& chown -R 4000:4000 /usr/share/nginx \
|
||||
&& chmod -R g+w /var/cache/nginx \
|
||||
&& touch /var/run/nginx.pid \
|
||||
&& chown -R 4000:4000 /var/run/nginx.pid \
|
||||
&& ln -sf /dev/stdout /var/log/nginx/access.log \
|
||||
&& ln -sf /dev/stderr /var/log/nginx/error.log
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
USER 4000
|
||||
|
||||
COPY nginx/nginx.conf /etc/nginx/conf.d
|
||||
COPY entrypoint.sh /
|
||||
|
||||
USER 0
|
||||
|
||||
RUN chmod +x entrypoint.sh
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
USER 4000
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
60
README.md
Normal file
60
README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# alfred-ui
|
||||
|
||||
### Install Yarn
|
||||
|
||||
```
|
||||
npm install yarn -g
|
||||
```
|
||||
|
||||
### Setup
|
||||
|
||||
Install dependencies
|
||||
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
In case of network timeout
|
||||
|
||||
```
|
||||
yarn install --network-timeout 1000000000
|
||||
```
|
||||
|
||||
Create following files in the project root.
|
||||
Ask the fellow devs for api keys and copy paste them in respective files.
|
||||
|
||||
```
|
||||
config.dev.js
|
||||
config.qa.js
|
||||
```
|
||||
|
||||
Start dev server with dev config
|
||||
|
||||
```
|
||||
yarn dev
|
||||
```
|
||||
|
||||
For production build
|
||||
|
||||
```
|
||||
yarn build
|
||||
yarn preview
|
||||
```
|
||||
|
||||
## Check Eslint-Prettier
|
||||
|
||||
```
|
||||
yarn eslint-check
|
||||
yarn lint
|
||||
yarn prettier-check
|
||||
```
|
||||
|
||||
```
|
||||
Please go through <strong>package.json</strong> for the scripts.
|
||||
```
|
||||
|
||||
```
|
||||
Useful Resources:
|
||||
1. Configure CSP ref: https://stackoverflow.com/questions/43453624/how-to-figure-out-a-reasonable-content-security-policy-source-for-nginx-virtual
|
||||
2. Verify your CSP using this link: https://csp-evaluator.withgoogle.com/
|
||||
```
|
||||
9
entrypoint.sh
Normal file
9
entrypoint.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
sed -i "s~<AUTH_BASE_URL>~${AUTH_BASE_URL}~g" /usr/share/nginx/html/config.js
|
||||
sed -i "s~<AUTH_CLIENT_ID>~${AUTH_CLIENT_ID}~g" /usr/share/nginx/html/config.js
|
||||
sed -i "s~<ENVIRONMENT>~${ENVIRONMENT}~g" /usr/share/nginx/html/config.js
|
||||
sed -i "s~<BASE_API_URL>~${BASE_API_URL}~g" /usr/share/nginx/html/config.js
|
||||
sed -i "s~CSP_HEADER~${CSP_HEADER}~g" /etc/nginx/conf.d/nginx.conf
|
||||
|
||||
exec "$@"
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
56
package.json
Normal file
56
package.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "houston-ui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"preview": "vite preview",
|
||||
"clear-build": "rm -rf dist",
|
||||
"local-copy-config": "cp config.qa.js config.js",
|
||||
"dev": "npm run local-copy-config && vite",
|
||||
"copy-config": "cp setup.template.js dist/config.js",
|
||||
"build": "npm run clear-build && tsc && vite build && npm run copy-config",
|
||||
"lint": "eslint --fix \"**/?*.{ts,tsx,js,jsx}\"",
|
||||
"eslint-check": "eslint \"**/?*.{ts,tsx,js,jsx}\"",
|
||||
"prepare": "husky install",
|
||||
"pretty": "prettier --write \"./**/*.{js,jsx,ts,tsx,css,scss,md}\"",
|
||||
"prettier-check": "prettier --check \"./**/*.{js,jsx,ts,tsx,css,scss,md}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@navi/web-ui": "^1.49.8",
|
||||
"@super-app/dark-knight": "^1.0.6",
|
||||
"axios": "^1.3.4",
|
||||
"classnames": "^2.3.2",
|
||||
"node-sass": "^8.0.0",
|
||||
"path": "^0.12.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.8.2",
|
||||
"sass": "^1.58.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
||||
"@typescript-eslint/parser": "^5.54.1",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-prettier": "^8.7.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.3",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"husky": "^8.0.3",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-nested": "^6.0.1",
|
||||
"postcss-prefix-selector": "^1.16.0",
|
||||
"prettier": "^2.8.4",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.2.0"
|
||||
}
|
||||
}
|
||||
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
7
setup.template.js
Normal file
7
setup.template.js
Normal file
@@ -0,0 +1,7 @@
|
||||
window.config = {
|
||||
AUTH_BASE_URL: '<AUTH_BASE_URL>',
|
||||
AUTH_CLIENT_ID: '<AUTH_CLIENT_ID>',
|
||||
ENVIRONMENT: '<ENVIRONMENT>',
|
||||
BASE_API_URL: '<BASE_API_URL>',
|
||||
CSP_HEADER: '<CSP_HEADER>',
|
||||
};
|
||||
53
src/App.tsx
Normal file
53
src/App.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import DarkKnight from '@super-app/dark-knight';
|
||||
import { toast } from '@navi/web-ui/lib/primitives/Toast/index';
|
||||
|
||||
import AppRouter from './AppRouter';
|
||||
|
||||
const config = window.config ?? {};
|
||||
|
||||
const initOptions = {
|
||||
url: config.AUTH_BASE_URL,
|
||||
clientId: config.AUTH_CLIENT_ID,
|
||||
onLoad: 'login-required',
|
||||
};
|
||||
|
||||
const auth = DarkKnight(initOptions);
|
||||
|
||||
const App = () => {
|
||||
useEffect(() => {
|
||||
if (window?.config?.ENVIRONMENT === 'production') {
|
||||
const token = localStorage.getItem('react-token');
|
||||
auth
|
||||
.init({
|
||||
onLoad: 'check-sso',
|
||||
sessionToken: token ?? undefined,
|
||||
enableLogging: true,
|
||||
})
|
||||
.then((authenticated: boolean) => {
|
||||
if (!authenticated) {
|
||||
auth.login({
|
||||
redirectUri: `${window.location.protocol}//${window.location.host}/agent/login/?redirectUri=${window.location.href}`,
|
||||
});
|
||||
}
|
||||
localStorage.setItem('react-token', auth.sessionToken ?? '');
|
||||
localStorage.setItem(
|
||||
'user-data',
|
||||
JSON.stringify(auth.idTokenParsed) ?? '',
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
if (error?.response?.status === 403) {
|
||||
toast.error(
|
||||
'You are not authorized to perform this action. Permission denied!',
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <AppRouter />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
28
src/AppRouter.tsx
Normal file
28
src/AppRouter.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { FC } from 'react';
|
||||
import { Routes, Route, Outlet } from 'react-router-dom';
|
||||
|
||||
import LeftNav from './components/LeftNav';
|
||||
|
||||
import routes from './router';
|
||||
|
||||
const AppRouter: FC = () => (
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<LeftNav>
|
||||
<Outlet />
|
||||
</LeftNav>
|
||||
}
|
||||
>
|
||||
{routes.map(component => (
|
||||
<Route
|
||||
key={component?.id}
|
||||
path={component?.path}
|
||||
element={component?.element}
|
||||
/>
|
||||
))}
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
|
||||
export default AppRouter;
|
||||
7
src/Pages/Dashboard/index.tsx
Normal file
7
src/Pages/Dashboard/index.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
const Dashboard: FC = () => {
|
||||
return (<>In Dashboard Page!</>);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
35
src/assets/NavLogoPlaceholder.tsx
Normal file
35
src/assets/NavLogoPlaceholder.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
import { IconProps } from './types';
|
||||
|
||||
const NavLogoPlaceholder: React.FC<IconProps> = ({
|
||||
width = '24',
|
||||
height = '24',
|
||||
fillColor = '#969696',
|
||||
}) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
x="0.5"
|
||||
y="0.5"
|
||||
width="23"
|
||||
height="23"
|
||||
rx="3.5"
|
||||
fill="white"
|
||||
stroke="#E8E8E8"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M8.57147 12.5713C8.25719 12.5713 8.00004 12.8284 8.00004 13.1427C8.00004 13.457 8.25719 13.7141 8.57147 13.7141C8.88576 13.7141 9.1429 13.457 9.1429 13.1427C9.1429 12.8284 8.88576 12.5713 8.57147 12.5713ZM8.57147 14.857C8.25719 14.857 8.00004 15.1141 8.00004 15.4284C8.00004 15.7427 8.25719 15.9999 8.57147 15.9999C8.88576 15.9999 9.1429 15.7427 9.1429 15.4284C9.1429 15.1141 8.88576 14.857 8.57147 14.857ZM8.57147 10.2856C8.25719 10.2856 8.00004 10.5427 8.00004 10.857C8.00004 11.1713 8.25719 11.4284 8.57147 11.4284C8.88576 11.4284 9.1429 11.1713 9.1429 10.857C9.1429 10.5427 8.88576 10.2856 8.57147 10.2856ZM6.85719 10.5713C6.69719 10.5713 6.57147 10.697 6.57147 10.857C6.57147 11.017 6.69719 11.1427 6.85719 11.1427C7.01719 11.1427 7.1429 11.017 7.1429 10.857C7.1429 10.697 7.01719 10.5713 6.85719 10.5713ZM8.57147 7.99986C8.25719 7.99986 8.00004 8.257 8.00004 8.57129C8.00004 8.88557 8.25719 9.14272 8.57147 9.14272C8.88576 9.14272 9.1429 8.88557 9.1429 8.57129C9.1429 8.257 8.88576 7.99986 8.57147 7.99986ZM17.1429 11.1427C17.3029 11.1427 17.4286 11.017 17.4286 10.857C17.4286 10.697 17.3029 10.5713 17.1429 10.5713C16.9829 10.5713 16.8572 10.697 16.8572 10.857C16.8572 11.017 16.9829 11.1427 17.1429 11.1427ZM13.1429 9.14272C13.4572 9.14272 13.7143 8.88557 13.7143 8.57129C13.7143 8.257 13.4572 7.99986 13.1429 7.99986C12.8286 7.99986 12.5715 8.257 12.5715 8.57129C12.5715 8.88557 12.8286 9.14272 13.1429 9.14272ZM13.1429 7.14272C13.3029 7.14272 13.4286 7.017 13.4286 6.857C13.4286 6.697 13.3029 6.57129 13.1429 6.57129C12.9829 6.57129 12.8572 6.697 12.8572 6.857C12.8572 7.017 12.9829 7.14272 13.1429 7.14272ZM6.85719 12.857C6.69719 12.857 6.57147 12.9827 6.57147 13.1427C6.57147 13.3027 6.69719 13.4284 6.85719 13.4284C7.01719 13.4284 7.1429 13.3027 7.1429 13.1427C7.1429 12.9827 7.01719 12.857 6.85719 12.857ZM10.8572 16.857C10.6972 16.857 10.5715 16.9827 10.5715 17.1427C10.5715 17.3027 10.6972 17.4284 10.8572 17.4284C11.0172 17.4284 11.1429 17.3027 11.1429 17.1427C11.1429 16.9827 11.0172 16.857 10.8572 16.857ZM10.8572 7.14272C11.0172 7.14272 11.1429 7.017 11.1429 6.857C11.1429 6.697 11.0172 6.57129 10.8572 6.57129C10.6972 6.57129 10.5715 6.697 10.5715 6.857C10.5715 7.017 10.6972 7.14272 10.8572 7.14272ZM10.8572 9.14272C11.1715 9.14272 11.4286 8.88557 11.4286 8.57129C11.4286 8.257 11.1715 7.99986 10.8572 7.99986C10.5429 7.99986 10.2858 8.257 10.2858 8.57129C10.2858 8.88557 10.5429 9.14272 10.8572 9.14272ZM10.8572 12.2856C10.3829 12.2856 10 12.6684 10 13.1427C10 13.617 10.3829 13.9999 10.8572 13.9999C11.3315 13.9999 11.7143 13.617 11.7143 13.1427C11.7143 12.6684 11.3315 12.2856 10.8572 12.2856ZM15.4286 12.5713C15.1143 12.5713 14.8572 12.8284 14.8572 13.1427C14.8572 13.457 15.1143 13.7141 15.4286 13.7141C15.7429 13.7141 16 13.457 16 13.1427C16 12.8284 15.7429 12.5713 15.4286 12.5713ZM15.4286 14.857C15.1143 14.857 14.8572 15.1141 14.8572 15.4284C14.8572 15.7427 15.1143 15.9999 15.4286 15.9999C15.7429 15.9999 16 15.7427 16 15.4284C16 15.1141 15.7429 14.857 15.4286 14.857ZM15.4286 10.2856C15.1143 10.2856 14.8572 10.5427 14.8572 10.857C14.8572 11.1713 15.1143 11.4284 15.4286 11.4284C15.7429 11.4284 16 11.1713 16 10.857C16 10.5427 15.7429 10.2856 15.4286 10.2856ZM15.4286 7.99986C15.1143 7.99986 14.8572 8.257 14.8572 8.57129C14.8572 8.88557 15.1143 9.14272 15.4286 9.14272C15.7429 9.14272 16 8.88557 16 8.57129C16 8.257 15.7429 7.99986 15.4286 7.99986ZM17.1429 12.857C16.9829 12.857 16.8572 12.9827 16.8572 13.1427C16.8572 13.3027 16.9829 13.4284 17.1429 13.4284C17.3029 13.4284 17.4286 13.3027 17.4286 13.1427C17.4286 12.9827 17.3029 12.857 17.1429 12.857ZM13.1429 14.857C12.8286 14.857 12.5715 15.1141 12.5715 15.4284C12.5715 15.7427 12.8286 15.9999 13.1429 15.9999C13.4572 15.9999 13.7143 15.7427 13.7143 15.4284C13.7143 15.1141 13.4572 14.857 13.1429 14.857ZM13.1429 16.857C12.9829 16.857 12.8572 16.9827 12.8572 17.1427C12.8572 17.3027 12.9829 17.4284 13.1429 17.4284C13.3029 17.4284 13.4286 17.3027 13.4286 17.1427C13.4286 16.9827 13.3029 16.857 13.1429 16.857ZM10.8572 9.99986C10.3829 9.99986 10 10.3827 10 10.857C10 11.3313 10.3829 11.7141 10.8572 11.7141C11.3315 11.7141 11.7143 11.3313 11.7143 10.857C11.7143 10.3827 11.3315 9.99986 10.8572 9.99986ZM10.8572 14.857C10.5429 14.857 10.2858 15.1141 10.2858 15.4284C10.2858 15.7427 10.5429 15.9999 10.8572 15.9999C11.1715 15.9999 11.4286 15.7427 11.4286 15.4284C11.4286 15.1141 11.1715 14.857 10.8572 14.857ZM13.1429 12.2856C12.6686 12.2856 12.2858 12.6684 12.2858 13.1427C12.2858 13.617 12.6686 13.9999 13.1429 13.9999C13.6172 13.9999 14 13.617 14 13.1427C14 12.6684 13.6172 12.2856 13.1429 12.2856ZM13.1429 9.99986C12.6686 9.99986 12.2858 10.3827 12.2858 10.857C12.2858 11.3313 12.6686 11.7141 13.1429 11.7141C13.6172 11.7141 14 11.3313 14 10.857C14 10.3827 13.6172 9.99986 13.1429 9.99986Z"
|
||||
fill={fillColor}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default NavLogoPlaceholder;
|
||||
1
src/assets/react.svg
Normal file
1
src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
7
src/assets/types.ts
Normal file
7
src/assets/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface IconProps {
|
||||
fillColor?: string;
|
||||
height?: number;
|
||||
width?: number;
|
||||
color?: string;
|
||||
[x: string | number | symbol]: unknown;
|
||||
}
|
||||
54
src/components/Dialog/Dialog.module.scss
Normal file
54
src/components/Dialog/Dialog.module.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
.dialog-container {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
visibility: hidden;
|
||||
background: rgba(28, 28, 28, 0);
|
||||
transition: all 0.5s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
.dialog {
|
||||
width: 408px;
|
||||
max-height: 70%;
|
||||
min-height: fit-content;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
background: var(--navi-color-gray-bg-primary);
|
||||
box-shadow: var(--navi-shadow-drop-3);
|
||||
transition: all 0.5s;
|
||||
transform: translateY(100%);
|
||||
position: relative;
|
||||
padding: 24px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.close-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&--without-text {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-open {
|
||||
background: rgba(28, 28, 28, 0.6);
|
||||
visibility: visible;
|
||||
transition: all 0.5s;
|
||||
.dialog {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
}
|
||||
87
src/components/Dialog/index.tsx
Normal file
87
src/components/Dialog/index.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import CloseIcon from '@navi/web-ui/lib/icons/CloseIcon/CloseIcon';
|
||||
import { Button, Typography } from '@navi/web-ui/lib/primitives';
|
||||
import ReactPortal from '@navi/web-ui/lib/primitives/ReactPortal/index';
|
||||
import { DialogProps } from './types';
|
||||
import styles from './Dialog.module.scss';
|
||||
|
||||
const Dialog: React.FC<DialogProps> = props => {
|
||||
const {
|
||||
open,
|
||||
onClose,
|
||||
header = '',
|
||||
showFooter,
|
||||
footerButtons,
|
||||
children,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const dialogContainerStyles = cx(styles['dialog-container'], {
|
||||
[styles['is-open']]: open,
|
||||
});
|
||||
|
||||
const handleClose = (): void => {
|
||||
document.body.style.overflow = 'unset';
|
||||
onClose();
|
||||
};
|
||||
|
||||
const renderHeader = (): JSX.Element => {
|
||||
const headerStyles = cx(styles.header, {
|
||||
[styles['header--without-text']]: header === '',
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={headerStyles}>
|
||||
{header !== '' && <Typography variant="h3">{header}</Typography>}
|
||||
<CloseIcon
|
||||
size="md"
|
||||
onClick={handleClose}
|
||||
className={styles['close-icon']}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderFooter = (): JSX.Element | false =>
|
||||
showFooter && (
|
||||
<div className={styles.footer}>
|
||||
{footerButtons.map((cta, index) => {
|
||||
const { label, onClick } = cta;
|
||||
return (
|
||||
<Button
|
||||
variant={index % 2 === 0 ? 'secondary' : 'primary'}
|
||||
key={label}
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (open) document.body.style.overflow = 'hidden';
|
||||
|
||||
return (
|
||||
<ReactPortal wrapperId="dialogPortal">
|
||||
<main
|
||||
role="presentation"
|
||||
className={dialogContainerStyles}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<section
|
||||
className={styles.dialog}
|
||||
onClick={e => e.stopPropagation()}
|
||||
{...restProps}
|
||||
>
|
||||
{renderHeader()}
|
||||
{children}
|
||||
{renderFooter()}
|
||||
</section>
|
||||
</main>
|
||||
</ReactPortal>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dialog;
|
||||
11
src/components/Dialog/types.ts
Normal file
11
src/components/Dialog/types.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export interface DialogProps extends React.ComponentPropsWithRef<'div'> {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
showFooter: boolean;
|
||||
footerButtons: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
}[];
|
||||
header?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
6
src/components/Fallback/Fallback.module.scss
Normal file
6
src/components/Fallback/Fallback.module.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
.fallback-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
27
src/components/Fallback/index.tsx
Normal file
27
src/components/Fallback/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
|
||||
import cx from 'classnames';
|
||||
|
||||
import LoadingIcon from '@navi/web-ui/lib/icons/LoadingIcon/LoadingIcon';
|
||||
import styles from './Fallback.module.scss';
|
||||
|
||||
interface FallbackComponentProps {
|
||||
customClassName?: string;
|
||||
[x: string | number | symbol]: unknown;
|
||||
}
|
||||
|
||||
const FallbackComponent: React.FC<FallbackComponentProps> = ({
|
||||
customClassName = '',
|
||||
...restProps
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cx(styles['fallback-container'], customClassName)}
|
||||
{...restProps}
|
||||
>
|
||||
<LoadingIcon size="lg" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FallbackComponent;
|
||||
29
src/components/LeftNav/LeftNav.module.scss
Normal file
29
src/components/LeftNav/LeftNav.module.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
.page-content-container {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
transition: all ease-out 0.5s;
|
||||
margin: 12px 12px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: inline-flex;
|
||||
gap: 16px;
|
||||
min-width: max-content;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
margin: 24px 0px;
|
||||
}
|
||||
|
||||
.expanded-page-content {
|
||||
margin-left: 212px;
|
||||
transition: all ease-out 0.5s;
|
||||
}
|
||||
|
||||
.platform-header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
135
src/components/LeftNav/index.tsx
Normal file
135
src/components/LeftNav/index.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import React, { useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Navbar } from '@navi/web-ui/lib/components';
|
||||
import DashboardIcon from '@navi/web-ui/lib/icons/DashboardIcon/DashboardIcon';
|
||||
import { NavItemType } from '@navi/web-ui/lib/components/Navbar/types';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
|
||||
import NavLogoPlaceholder from '@src/assets/NavLogoPlaceholder';
|
||||
|
||||
import Dialog from '../Dialog';
|
||||
import styles from './LeftNav.module.scss';
|
||||
|
||||
interface LeftNavProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const LeftNav: React.FC<LeftNavProps> = ({ children }) => {
|
||||
const navigate = useNavigate();
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const userDetails = localStorage.getItem('user-data');
|
||||
|
||||
const openDialog = (): void => setDialogOpen(true);
|
||||
const closeDialog = (): void => setDialogOpen(false);
|
||||
|
||||
const confirmLogout = (): void => {
|
||||
closeDialog();
|
||||
localStorage.removeItem('react-token');
|
||||
localStorage.removeItem('user-data');
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const handleExpandChange = (isExpanded: boolean): void => {
|
||||
setIsExpanded(isExpanded);
|
||||
};
|
||||
|
||||
const navItemsList: NavItemType[] = [
|
||||
{
|
||||
itemType: 'simpleNavItem',
|
||||
label: 'Dashboard',
|
||||
route: '/',
|
||||
Icon: DashboardIcon,
|
||||
handleNavigation: () => navigate('/'),
|
||||
},
|
||||
];
|
||||
|
||||
const returnUserData = (): string => {
|
||||
if (userDetails?.length) {
|
||||
try {
|
||||
const parsedUserData = JSON.parse(userDetails);
|
||||
return parsedUserData?.preferred_username || 'User';
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
return 'User';
|
||||
};
|
||||
|
||||
const footerDetails = {
|
||||
footerText: returnUserData(),
|
||||
options: [
|
||||
{
|
||||
label: 'Logout',
|
||||
handleClick: openDialog,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const headerContent: JSX.Element = (
|
||||
<div>
|
||||
<div className={styles.header}>
|
||||
<NavLogoPlaceholder width={24} height={24} />
|
||||
{isExpanded && (
|
||||
<Typography variant="p2" color="white">
|
||||
Houston UI
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<div className={styles['platform-header']}>
|
||||
<Typography variant="p5" color="gray">
|
||||
Powered by Neon.
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Navbar
|
||||
headerContent={headerContent}
|
||||
navItemList={navItemsList}
|
||||
footer={footerDetails}
|
||||
handleNavbarStateChange={handleExpandChange}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
styles['page-content-container'],
|
||||
isExpanded ? styles['expanded-page-content'] : '',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Navbar>
|
||||
{dialogOpen && (
|
||||
<Dialog
|
||||
open={dialogOpen}
|
||||
onClose={closeDialog}
|
||||
header="Logout"
|
||||
showFooter
|
||||
footerButtons={[
|
||||
{
|
||||
label: 'Yes',
|
||||
onClick: confirmLogout,
|
||||
},
|
||||
{
|
||||
label: 'No',
|
||||
onClick: closeDialog,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<div className={styles['dialog-content']}>
|
||||
<Typography variant="p3">
|
||||
Are you sure you want to logout?
|
||||
</Typography>
|
||||
</div>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeftNav;
|
||||
6
src/components/ToastWrapper/index.tsx
Normal file
6
src/components/ToastWrapper/index.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { FC } from 'react';
|
||||
import { ToastContainer } from '@navi/web-ui/lib/primitives/Toast/components/ToastContainer';
|
||||
|
||||
const ToastWrapper: FC = () => <ToastContainer position="top-right" />;
|
||||
|
||||
export default ToastWrapper;
|
||||
9
src/index.css
Normal file
9
src/index.css
Normal file
@@ -0,0 +1,9 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
}
|
||||
19
src/main.tsx
Normal file
19
src/main.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import '@navi/web-ui/lib/styles/index.css';
|
||||
|
||||
import App from './App';
|
||||
import ToastWrapper from './components/ToastWrapper/index';
|
||||
|
||||
import './index.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<ToastWrapper />
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
19
src/router.tsx
Normal file
19
src/router.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { lazy } from 'react';
|
||||
|
||||
const Dashboard = lazy(() => import('./Pages/Dashboard/index'));
|
||||
|
||||
interface CustomRouteObject {
|
||||
id: string;
|
||||
path: string;
|
||||
element: JSX.Element;
|
||||
}
|
||||
|
||||
const routes: CustomRouteObject[] = [
|
||||
{
|
||||
id: 'DASHBOARD',
|
||||
path: '/',
|
||||
element: <Dashboard />,
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
72
src/services/api.ts
Normal file
72
src/services/api.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
export class ApiService {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: ApiService;
|
||||
|
||||
service: AxiosInstance = axios.create();
|
||||
|
||||
public static getInstance(): ApiService {
|
||||
if (!ApiService.instance) {
|
||||
ApiService.instance = new ApiService();
|
||||
// TODO: Uncomment this backend is sending Access-Control-Allow-Headers: x-session-token
|
||||
// ApiService.instance.service.interceptors.request.use((req: any) => {
|
||||
// req.headers['X-Session-Token'] =
|
||||
// localStorage.getItem('react-token') || '';
|
||||
// return req;
|
||||
// });
|
||||
}
|
||||
|
||||
return ApiService.instance;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-empty-function
|
||||
private constructor() {}
|
||||
|
||||
static get(path: any) {
|
||||
return ApiService.getInstance().instanceGet(path);
|
||||
}
|
||||
|
||||
static post(path: any, payload: any) {
|
||||
return ApiService.getInstance().instancePost(path, payload);
|
||||
}
|
||||
|
||||
static patch(path: any, payload: any) {
|
||||
return ApiService.getInstance().instancePatch(path, payload);
|
||||
}
|
||||
|
||||
static delete(path: any, payload = null) {
|
||||
return ApiService.getInstance().instanceDelete(path, payload);
|
||||
}
|
||||
|
||||
instanceGet(path: string) {
|
||||
return this.service.get(path);
|
||||
}
|
||||
|
||||
instancePatch(path: any, payload: any) {
|
||||
return this.service.request({
|
||||
method: 'PATCH',
|
||||
url: path,
|
||||
responseType: 'json',
|
||||
data: payload,
|
||||
});
|
||||
}
|
||||
|
||||
instancePost(path: any, payload: any) {
|
||||
return this.service.request({
|
||||
method: 'POST',
|
||||
url: path,
|
||||
responseType: 'json',
|
||||
data: payload,
|
||||
});
|
||||
}
|
||||
|
||||
instanceDelete(path: any, payload: null) {
|
||||
return this.service.request({
|
||||
method: 'DELETE',
|
||||
url: path,
|
||||
responseType: 'json',
|
||||
data: payload,
|
||||
});
|
||||
}
|
||||
}
|
||||
21
src/services/globalUtils.ts
Normal file
21
src/services/globalUtils.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export const returnHeaderConfig = () => {
|
||||
const userData = localStorage.getItem('user-data');
|
||||
const finalData = userData ? JSON.parse(userData) : 'null';
|
||||
const config = {
|
||||
headers: {
|
||||
'X-Session-Token': localStorage.getItem('react-token') || 'null',
|
||||
'X-Email-Id': finalData?.emailId || finalData,
|
||||
},
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
export const convertToCamelCase = (input: string): string => {
|
||||
let result = '';
|
||||
if (input.length) {
|
||||
result = input.replace(input[0], input.charAt(0).toLocaleLowerCase());
|
||||
result = result.replace(/ /g, '');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
16
src/types/index.d.ts
vendored
Normal file
16
src/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export {};
|
||||
|
||||
interface AppConfig {
|
||||
AUTH_BASE_URL: string;
|
||||
AUTH_CLIENT_ID: string;
|
||||
ENVIRONMENT: string;
|
||||
BASE_API_URL: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
config: AppConfig;
|
||||
}
|
||||
}
|
||||
|
||||
declare module '*.module.scss';
|
||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
content: ['./src/**/*.{tsx,html,js,jsx}'],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
corePlugins: {
|
||||
preflight: false,
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
32
tsconfig.json
Normal file
32
tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": false,
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@src/*": ["./*"],
|
||||
"@assets/*": ["assets/*"],
|
||||
"@components/*": ["components/*"],
|
||||
"@constants/*": ["constants/*"],
|
||||
"@hooks/*": ["hooks/*"],
|
||||
},
|
||||
"typeRoots": ["./node_modules/@types", "./src/types"]
|
||||
},
|
||||
"include": ["src", "config.js", "setup.template.js"],
|
||||
"exclude": ["**/node_modules/*"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
9
tsconfig.node.json
Normal file
9
tsconfig.node.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
15
vite.config.ts
Normal file
15
vite.config.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { resolve } from 'path';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@src': resolve(__dirname, './src'),
|
||||
'@components': resolve(__dirname, './src/components'),
|
||||
'@navi/web-ui': resolve(__dirname, './node_modules/@navi/web-ui'),
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user