dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
15 changed files with 5318 additions and 140 deletions
Showing only changes of commit 2e417c46af - Show all commits

View file

@ -1,6 +1,8 @@
{ {
"trailingComma": "es5",
"tabWidth": 4, "tabWidth": 4,
"semi": false, "useTabs": true,
"singleQuote": false "semi": true,
} "singleQuote": false,
"bracketSpacing": true
}

View file

@ -1,5 +1,5 @@
{ {
"name": "digi-health-admin-dashboard", "name": "digi-ev-admin-dashboard",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -32,6 +32,7 @@
"mui-tel-input": "^7.0.0", "mui-tel-input": "^7.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^19.0.0", "react": "^19.0.0",
"react-cookie": "^7.2.2",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-dropzone": "^14.3.5", "react-dropzone": "^14.3.5",
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
@ -68,8 +69,8 @@
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.10.5", "@types/node": "^22.10.5",
"@types/react": "^19.0.3", "@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2", "@types/react-dom": "^19.0.2",
"typescript": "^5.7.2" "typescript": "^5.7.3"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -10,34 +10,12 @@
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. <title>DigiEV - Eco-friendly Charge</title>
-->
<title>React App</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>

View file

@ -1,12 +1,28 @@
import { BrowserRouter as Router} from 'react-router-dom'; import AppRouter from "./router";
import AppRouter from './router'; import { useSelector } from "react-redux";
import { useMatch, useNavigate, useSearchParams } from "react-router-dom";
import { useEffect } from "react";
import { RootState } from "./redux/store";
import { withCookies, ReactCookieProps } from "react-cookie";
function App() { const App: React.FC<ReactCookieProps> = ({ cookies }) => {
return ( const navigate = useNavigate();
<Router> const isPanel = useMatch("/auth/login");
<AppRouter /> const isCookiePresent = !!cookies?.get("authToken");
</Router> console.log("cookies present:", isCookiePresent);
const [searchParams] = useSearchParams();
const isAuthenticated = useSelector(
(state: RootState) => state.authReducer.isAuthenticated
); );
}
export default App; useEffect(() => {
if (isPanel && isCookiePresent) {
navigate("/panel/dashboard");
}
}, [isPanel, isAuthenticated, searchParams]);
return <AppRouter />;
};
export default withCookies(App);

View file

@ -11,6 +11,9 @@ import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded';
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded'; import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
import MenuButton from '../MenuButton'; import MenuButton from '../MenuButton';
import { Avatar } from '@mui/material'; import { Avatar } from '@mui/material';
import { useDispatch } from 'react-redux';
import { logoutUser } from '../../redux/slices/authSlice';
import { useCookies } from 'react-cookie';
const MenuItem = styled(MuiMenuItem)({ const MenuItem = styled(MuiMenuItem)({
margin: '2px 0', margin: '2px 0',
@ -19,12 +22,20 @@ const MenuItem = styled(MuiMenuItem)({
export default function OptionsMenu({ avatar }: { avatar?: boolean }) { export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const dispatch = useDispatch();
const [cookies, setCookie, removeCookie] = useCookies(['authToken']);
const handleClick = (event: React.MouseEvent<HTMLElement>) => { const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}; };
const handleClose = () => { const handleClose = () => {
setAnchorEl(null); setAnchorEl(null);
}; };
const handleLogout = () => {
dispatch(logoutUser({ removeCookie }));
console.log('click')
handleClose();
};
return ( return (
<React.Fragment> <React.Fragment>
<MenuButton <MenuButton
@ -70,7 +81,7 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
<MenuItem onClick={handleClose}>Settings</MenuItem> <MenuItem onClick={handleClose}>Settings</MenuItem>
<Divider /> <Divider />
<MenuItem <MenuItem
onClick={handleClose} onClick={handleLogout}
sx={{ sx={{
[`& .${listItemIconClasses.root}`]: { [`& .${listItemIconClasses.root}`]: {
ml: 'auto', ml: 'auto',

View file

@ -1,39 +1,22 @@
import { intersection, uniq } from 'lodash';
import React from 'react'; import React from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { checkUserAuth } from '../redux/slices/authSlice'; import { checkUserAuth } from '../redux/slices/authSlice';
const useAuth = (caps, { matchAllCaps = false }) => { const useAuth = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [isAuthorized, setIsAuthorized] = React.useState(false); const [isAuthorized, setIsAuthorized] = React.useState(false);
const { isAuthenticated } = useSelector((state) => ({
const { isAuthenticated, userCapabilities } = useSelector((state) => ({
isAuthenticated: state.authReducer.isAuthenticated, isAuthenticated: state.authReducer.isAuthenticated,
userCapabilities: state.authReducer.userCapabilities,
})); }));
const requiredCaps = React.useMemo(
() => uniq(Array.isArray(caps) ? caps : [caps]),
[caps]
);
React.useEffect(() => { React.useEffect(() => {
const userMatchedCaps = intersection(userCapabilities, requiredCaps); if (isAuthenticated) {
let isUserAuthorized = matchAllCaps
? userMatchedCaps?.length === requiredCaps?.length
: userMatchedCaps?.length > 0;
if (requiredCaps.length === 0) {
isUserAuthorized = true;
}
// if (isAuthenticated === null) {
if (isAuthenticated === null || false || undefined) {
dispatch(checkUserAuth()); dispatch(checkUserAuth());
} else { } else {
setIsAuthorized(isAuthenticated && isUserAuthorized); setIsAuthorized(false);
} }
}, [dispatch, isAuthenticated, requiredCaps, userCapabilities]); }, [dispatch, isAuthenticated]);
return { isAuthenticated, isAuthorized }; return { isAuthenticated, isAuthorized };
}; };

View file

@ -1,29 +1,32 @@
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom/client'; import ReactDOM from "react-dom/client";
import './index.css'; import "./index.css";
import reportWebVitals from './reportWebVitals'; import App from "./App";
import App from './App'; import { Provider } from "react-redux";
import { Provider } from 'react-redux'; import store from "./redux/store";
import store from './redux/store/store.ts'; import { Slide, ToastContainer } from "react-toastify";
import { Slide, ToastContainer } from 'react-toastify'; import { BrowserRouter as Router } from "react-router-dom";
import { CookiesProvider } from "react-cookie";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<CookiesProvider defaultSetOptions={{ path: "/" }}>
<Provider store={store}> <Provider store={store}>
<Router>
<App /> <App />
</Router>
<ToastContainer <ToastContainer
autoClose={2000} autoClose={2000}
hideProgressBar hideProgressBar
theme="dark" theme="dark"
transition={Slide} transition={Slide}
toastStyle={{ border: '1px solid dimgray' }} toastStyle={{ border: "1px solid dimgray" }}
/> />
</Provider> </Provider>
</CookiesProvider>
</React.StrictMode> </React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View file

@ -213,7 +213,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
<Typography sx={{ textAlign: 'center' }}> <Typography sx={{ textAlign: 'center' }}>
Don&apos;t have an account?{' '} Don&apos;t have an account?{' '}
<Link <Link
href="/signup/" href="/auth/signup"
variant="body2" variant="body2"
sx={{ alignSelf: 'center' }} sx={{ alignSelf: 'center' }}
> >

View file

@ -117,11 +117,11 @@ const dispatch = useDispatch();
return ( return (
<AppTheme {...props}> <AppTheme {...props}>
<CssBaseline enableColorScheme /> {/* <CssBaseline enableColorScheme /> */}
<ColorModeSelect sx={{ position: 'fixed', top: '1rem', right: '1rem' }} /> <ColorModeSelect sx={{ position: 'fixed', top: '1rem', right: '1rem' }} />/
<SignUpContainer direction="column" justifyContent="space-between"> <SignUpContainer direction="column" justifyContent="space-between">
<Card variant="outlined"> <Card variant="outlined">
<SitemarkIcon /> Digi-EV
<Typography <Typography
component="h1" component="h1"
variant="h4" variant="h4"
@ -204,12 +204,12 @@ const dispatch = useDispatch();
/> />
</FormControl> </FormControl>
<MuiPhoneNumber <MuiPhoneNumber
defaultCountry='it' defaultCountry='in'
onChange={handleOnChange} onChange={handleOnChange}
value={phoneNumber} value={phoneNumber}
/> />
<FormControlLabel {/* <FormControlLabel
control={ control={
<Controller <Controller
name="allowExtraEmails" name="allowExtraEmails"
@ -220,16 +220,16 @@ const dispatch = useDispatch();
/> />
} }
label="I want to receive updates via email." label="I want to receive updates via email."
/> /> */}
<Button type="submit" fullWidth variant="contained"> <Button type="submit" fullWidth variant="contained">
Sign up Sign up
</Button> </Button>
</Box> </Box>
<Divider> {/* <Divider>
<Typography sx={{ color: 'text.secondary' }}>or</Typography> <Typography sx={{ color: 'text.secondary' }}>or</Typography>
</Divider> </Divider> */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}> {/* <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<Button <Button
fullWidth fullWidth
variant="outlined" variant="outlined"
@ -256,6 +256,19 @@ const dispatch = useDispatch();
Sign in Sign in
</Link> </Link>
</Typography> </Typography>
</Box> */}
<Divider>or</Divider>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<Typography sx={{ textAlign: 'center' }}>
Already have an account? &nbsp;
<Link
href="/auth/login"
variant="body2"
sx={{ alignSelf: 'center' }}
>
Sign in
</Link>
</Typography>
</Box> </Box>
</Card> </Card>
</SignUpContainer> </SignUpContainer>

View file

@ -0,0 +1,9 @@
import React from 'react'
function NotFoundPage() {
return (
<div>NotFoundPage</div>
)
}
export default NotFoundPage;

View file

@ -19,7 +19,7 @@ const categoryRows = [
]; ];
export default function Vehicles() { export default function Vehicles() {
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState<boolean>(false);
const [editRow, setEditRow] = useState<any>(null); const [editRow, setEditRow] = useState<any>(null);
const { reset } = useForm(); const { reset } = useForm();

11
src/redux/reducers.ts Normal file
View file

@ -0,0 +1,11 @@
import { combineReducers } from "@reduxjs/toolkit";
import authReducer from "./slices/authSlice";
const rootReducer = combineReducers({
authReducer,
});
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;

View file

@ -1,13 +1,10 @@
import { configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import authReducer from '../slices/authSlice.ts'
const store = configureStore({
reducer: {
auth: authReducer,
},
});
import rootReducer from './reducers';
export const store = configureStore({
reducer: rootReducer,
})
export type RootState = ReturnType<typeof store.getState>; export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch; export type AppDispatch = typeof store.dispatch;
export default store; export default store;

View file

@ -10,10 +10,11 @@
], ],
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"jsx": "react-jsx",
"types": ["react", "react-dom"],
"lib": ["dom", "dom.iterable", "esnext"],
"paths": { "paths": {
"@/*": [ "@/*": ["./src/*"]
"./src/*"
]
} }
} }
} }