Skip to content

Commit

Permalink
Merge pull request #23 from bcgov/zustand-setup
Browse files Browse the repository at this point in the history
Setup Modal provider with zustand
  • Loading branch information
jadmsaadaot authored Aug 1, 2024
2 parents 1436a43 + 86f8e16 commit 795249b
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 35 deletions.
3 changes: 2 additions & 1 deletion submit-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.52.1",
"react-oidc-context": "^3.1.0",
"yup": "^1.4.0"
"yup": "^1.4.0",
"zustand": "^4.5.4"
},
"devDependencies": {
"@cypress/code-coverage": "^3.12.44",
Expand Down
3 changes: 2 additions & 1 deletion submit-web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AuthProvider } from "react-oidc-context";
import { OidcConfig } from "@/utils/config";
import { theme } from "@/styles/theme";
import RouterProviderWithAuthContext from "@/router";

import ModalProvider from "./components/Shared/Modals/ModalProvider";
const queryClient = new QueryClient();

function App() {
Expand All @@ -15,6 +15,7 @@ function App() {
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<AuthProvider {...OidcConfig}>
<ModalProvider />
<RouterProviderWithAuthContext />
</AuthProvider>
</ThemeProvider>
Expand Down
22 changes: 8 additions & 14 deletions submit-web/src/components/App/Users/UserModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useModal } from "@/components/Shared/Modals/modalStore";
import { useAddUser, useUpdateUser } from "@/hooks/useUsers";
import { User } from "@/models/User";
import { Save } from "@mui/icons-material";
import {
Alert,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Expand All @@ -13,10 +13,8 @@ import {
import { useEffect, useState } from "react";

type AddUserModalProps = {
isOpen: boolean;
onClose: () => void;
onSubmit: () => void;
user?: User | null;
user: User | undefined;
};

const initFormData: Omit<User, "id"> = {
Expand All @@ -25,16 +23,12 @@ const initFormData: Omit<User, "id"> = {
username: "",
email_address: "",
contact_number: "",
description: ""
description: "",
};

const UserModal: React.FC<AddUserModalProps> = ({
isOpen,
onClose,
onSubmit,
user,
}) => {
const UserModal: React.FC<AddUserModalProps> = ({ onSubmit, user }) => {
const [formData, setFormData] = useState<Omit<User, "id">>(initFormData);
const {setClose} = useModal();

useEffect(() => {
if (user) {
Expand Down Expand Up @@ -90,11 +84,11 @@ const UserModal: React.FC<AddUserModalProps> = ({
const handleClose = () => {
reset();
setFormData(initFormData);
onClose();
setClose();
};

return (
<Dialog open={isOpen} onClose={handleClose}>
<>
<DialogTitle fontWeight={"bold"}>Add New User</DialogTitle>
<form onSubmit={handleSubmit}>
<DialogContent>
Expand Down Expand Up @@ -151,7 +145,7 @@ const UserModal: React.FC<AddUserModalProps> = ({
</Button>
</DialogActions>
</form>
</Dialog>
</>
);
};

Expand Down
15 changes: 15 additions & 0 deletions submit-web/src/components/Shared/Modals/ModalProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { useModal } from "./modalStore";
import { Box, Modal } from "@mui/material";

const ModalProvider: React.FC = () => {
const { modalContent, setClose, isOpen } = useModal();

return (
<Modal open={isOpen} onClose={setClose}>
<Box>{modalContent}</Box>
</Modal>
);
};

export default ModalProvider;
55 changes: 55 additions & 0 deletions submit-web/src/components/Shared/Modals/UpdateModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Button, Grid, Typography } from "@mui/material";
import { useModal } from "./modalStore";
import { modalStyle } from "./constants";

interface UpdateModalProps {
header: string;
subText: { text: string; bold?: boolean }[];
}

const UpdateModal = ({ header, subText }: UpdateModalProps) => {
const { setClose } = useModal();

return (
<Grid
container
direction="row"
justifyContent="flex-start"
alignItems="space-between"
rowSpacing={2}
sx={{ ...modalStyle }}
>
<Grid container direction="row" item xs={12}>
<Grid item xs={12}>
<Typography variant="h1" sx={{ mb: 2 }}>
{header}
</Typography>
</Grid>
</Grid>
<Grid container direction="row" item xs={12}>
{subText.map((subtext) => (
<Grid item xs={12}>
<Typography variant="body1" sx={{ mb: 1 }}>
{subtext.text}
</Typography>
</Grid>
))}
<Grid
item
container
direction={{ xs: "column", sm: "row" }}
xs={12}
justifyContent="flex-end"
spacing={1}
sx={{ mt: "1em" }}
>
<Button onClick={setClose} sx={{ m: 1 }}>
Close
</Button>
</Grid>
</Grid>
</Grid>
);
};

export default UpdateModal;
18 changes: 18 additions & 0 deletions submit-web/src/components/Shared/Modals/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { theme } from "@/styles/theme";

export const modalStyle = {
position: 'absolute',
top: '50%',
left: '48%',
transform: 'translate(-50%, -50%)',
maxWidth: 'min(95vw, 700px)',
maxHeight: '95vh',
bgcolor: 'background.paper',
boxShadow: 10,
pt: 2,
px: 4,
pb: 3,
m: 1,
overflowY: 'scroll',
color: theme.palette.text.primary,
};
45 changes: 45 additions & 0 deletions submit-web/src/components/Shared/Modals/modalStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {create} from 'zustand'
import { User } from "@/models/User";
import { Plan } from '@/models/Plan';


// Define the ModalData type
export type ModalData = {
user?: User
plan?: Plan
}

// Define the store state and actions
interface ModalStore {
data: ModalData
isOpen: boolean
modalContent: React.ReactNode | null
setOpen: (modal: React.ReactNode, fetchData?: () => Promise<ModalData>) => Promise<void>
setClose: () => void
}

// Create the Zustand store
export const useModal = create<ModalStore>((set) => ({
data: {},
isOpen: false,
modalContent: null,

setOpen: async (modal, fetchData) => {
if (modal) {
const fetchedData = fetchData ? await fetchData() : {}
set((state) => ({
data: { ...state.data, ...fetchedData },
modalContent: modal,
isOpen: true,
}))
}
},

setClose: () => {
set({
isOpen: false,
data: {},
modalContent: null,
})
},
}))
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ControlledTextField from "@/components/Shared/controlled/ControlledTextFi
import { theme } from "@/styles/theme";

export const Route = createFileRoute(
"/_authenticated/registration/create-account",
"/_authenticated/registration/create-account"
)({
component: CreateAccount,
});
Expand All @@ -37,7 +37,7 @@ function CreateAccount() {
() => navigate({ to: "/projects" }),
() => {
return;
},
}
);

const methods = useForm({
Expand Down
28 changes: 11 additions & 17 deletions submit-web/src/routes/_authenticated/users/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import CustomSnackbar, {
SnackBarMessageProps,
} from "@/components/Shared/Popups/SnackBarMessage";
import UserModal from "@/components/App/Users/UserModal";
import { useModal } from "@/components/Shared/Modals/modalStore";

export const Route = createFileRoute("/_authenticated/users/")({
component: UsersPage,
});

function UsersPage() {
const queryClient = useQueryClient();
const [isModalOpen, setIsModalOpen] = useState(false);
const { setOpen } = useModal();
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [isConfirmationOpen, setIsConfirmationOpen] = useState(false);
const [userIdToDelete, setUserIdToDelete] = useState<number | null>(null);
Expand All @@ -46,17 +47,11 @@ function UsersPage() {
} else {
setSnackbarConfig({ message: "User added successfully!" });
}
handleCloseModal();
};

const handleOpenModal = (user?: User) => {
setOpen(<UserModal user={user} onSubmit={handleOnSubmit} />);
setSelectedUser(user || null);
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
setSelectedUser(null);
};

/** Delete user START */
Expand All @@ -68,8 +63,11 @@ function UsersPage() {
});
};

const onDeleteError = (error: AxiosError) => {
setSnackbarConfig({ message: `User deletion failed! ${error.message}`, severity: "error" });
const onDeleteError = (error: AxiosError) => {
setSnackbarConfig({
message: `User deletion failed! ${error.message}`,
severity: "error",
});
};

const { mutate: deleteUser } = useDeleteUser(onDeleteSuccess, onDeleteError);
Expand Down Expand Up @@ -140,7 +138,9 @@ function UsersPage() {
key={row.id}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row">{row.first_name}</TableCell>
<TableCell component="th" scope="row">
{row.first_name}
</TableCell>
<TableCell>{row.last_name}</TableCell>
<TableCell>{row.username}</TableCell>
<TableCell>{row.email_address}</TableCell>
Expand All @@ -165,12 +165,6 @@ function UsersPage() {
</TableBody>
</Table>
</TableContainer>
<UserModal
isOpen={isModalOpen}
onClose={handleCloseModal}
onSubmit={handleOnSubmit}
user={selectedUser}
></UserModal>
<ConfirmationDialog
isOpen={isConfirmationOpen}
title="Delete User"
Expand Down

0 comments on commit 795249b

Please sign in to comment.