Skip to content

Commit 25419a7

Browse files
limlindsayjNameless7631IsaacNguyenshowmentsrukelman
authored
Admin Settings Styling and Functionality (#159)
* logging in now reroutes you to authentification page, styling done for 2fa warning pop up * fix: now allows login when switching roles * temp console log * styling and table drawer * edit email drawer for admin * case manager edit email * confirm email change modal * feat: add modals, alerts, functionality * remove log --------- Co-authored-by: Nathan Nguyen <nathnguyen7631@gmail.com> Co-authored-by: Isaac Nguyen <isaachn@uci.edu> Co-authored-by: SoulSen <talukdershowmen@gmail.com> Co-authored-by: Sean Kelman <seanrkelman@gmail.com>
1 parent 982fccd commit 25419a7

File tree

14 files changed

+1753
-649
lines changed

14 files changed

+1753
-649
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
import { useEffect, useState } from "react";
2+
3+
4+
import { ChevronRightIcon } from "@chakra-ui/icons";
5+
import {
6+
Button,
7+
Drawer,
8+
DrawerBody,
9+
DrawerContent,
10+
DrawerHeader,
11+
HStack,
12+
IconButton,
13+
Table,
14+
TableContainer,
15+
Tbody,
16+
Td,
17+
Text,
18+
Tr, useDisclosure,
19+
useToast,
20+
} from "@chakra-ui/react";
21+
22+
23+
import { useBackendContext } from "../../contexts/hooks/useBackendContext.ts";
24+
import { SelectInputComponent, TextInputComponent } from "../intakeStatsForm/formComponents.tsx";
25+
import { RoleKey } from "./ManageAccounts.tsx";
26+
import { CancelAddModal } from "./CancelAddModal.tsx";
27+
28+
type UserInfo = {
29+
firstName: string;
30+
lastName: string;
31+
email: string;
32+
phoneNumber: string;
33+
location: string;
34+
notes: string;
35+
}
36+
37+
type LocationOption = {
38+
label: string;
39+
value: string;
40+
};
41+
42+
type Location = {
43+
id: number;
44+
cm_id: number;
45+
name: string;
46+
date: Date;
47+
caloptima_funded: boolean;
48+
};
49+
50+
const AddPreview = ({
51+
userType,
52+
isOpen,
53+
onClose,
54+
}: {
55+
userType: RoleKey;
56+
isOpen: boolean;
57+
onClose: () => void;
58+
}) => {
59+
const { backend } = useBackendContext();
60+
61+
const [locationOptions, setLocationOption] = useState<LocationOption[]>([]);
62+
const [newUser, setNewUser] = useState<UserInfo>({
63+
firstName: "",
64+
lastName: "",
65+
email: "",
66+
phoneNumber: "",
67+
location: "",
68+
notes: ""
69+
});
70+
const toast = useToast();
71+
72+
const userTypeName = {
73+
admin: "Admin",
74+
cms: "Case Manager",
75+
clients: "Client",
76+
};
77+
78+
const title = userTypeName[userType];
79+
80+
const {
81+
isOpen: modalIsOpen,
82+
onOpen: modalOnOpen,
83+
onClose: modalOnClose
84+
} = useDisclosure();
85+
86+
const submitUser = async () => {
87+
try {
88+
const roleDict = {
89+
admin: "admin",
90+
cms: "case_manager",
91+
clients: "client"
92+
};
93+
94+
if (roleDict[userType] === "client") {
95+
return;
96+
}
97+
98+
for (const value of Object.values(newUser)) {
99+
if (value === "") {
100+
toast({
101+
title: `Missing Information`,
102+
description: `There is a missing or incorrect field.`,
103+
status: "warning",
104+
duration: 9000,
105+
isClosable: true,
106+
});
107+
108+
return;
109+
}
110+
}
111+
112+
await backend.post(`/caseManagers`, {
113+
role: roleDict[userType],
114+
firstName: newUser.firstName,
115+
lastName: newUser.lastName,
116+
phoneNumber: newUser.phoneNumber,
117+
email: newUser.email,
118+
notes: newUser.notes
119+
});
120+
121+
onClose();
122+
123+
toast({
124+
title: `${title} Added`,
125+
description: `${newUser.firstName} ${newUser.lastName} has been added!`,
126+
status: "success",
127+
duration: 9000,
128+
isClosable: true,
129+
});
130+
} catch (e) {
131+
console.error(e);
132+
133+
toast({
134+
title: `${title} Not Added`,
135+
description: `An error occurred and the ${title.toLowerCase()} was not added`,
136+
status: "error",
137+
duration: 9000,
138+
isClosable: true,
139+
});
140+
}
141+
}
142+
143+
useEffect(() => {
144+
const getLocations = async () => {
145+
try {
146+
const response = await backend.get("/locations");
147+
const locationOptions: LocationOption[] = [];
148+
149+
response.data.forEach((location: Location) => {
150+
locationOptions.push({
151+
label: location.name,
152+
value: location.name,
153+
});
154+
});
155+
156+
setLocationOption(locationOptions);
157+
} catch (e) {
158+
console.error(`something went wrong ${e}`);
159+
}
160+
};
161+
162+
getLocations();
163+
}, [backend, setLocationOption]);
164+
165+
const handleChange = (
166+
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>,
167+
) => {
168+
const { name, value } = e.target;
169+
170+
if (name === "name") {
171+
const name = value.split(" ");
172+
173+
if (name.length >= 2) {
174+
setNewUser((prev) => ({
175+
...prev,
176+
firstName: name[0] ?? "",
177+
lastName: name[1] ?? "",
178+
}));
179+
180+
return;
181+
}
182+
}
183+
184+
setNewUser((prev) => ({
185+
...prev,
186+
[name]: value,
187+
}));
188+
};
189+
190+
return (
191+
<Drawer
192+
isOpen={isOpen}
193+
onClose={onClose}
194+
size="lg"
195+
>
196+
<DrawerContent>
197+
<DrawerHeader borderBottomWidth="1px">
198+
<HStack spacing={2}>
199+
<IconButton
200+
as={ChevronRightIcon}
201+
color="blue.500"
202+
aria-label="Close drawer"
203+
onClick={modalOnOpen}
204+
variant="ghost"
205+
size="sm"
206+
/>
207+
<Text fontSize="md">Add {title}</Text>
208+
</HStack>
209+
</DrawerHeader>
210+
211+
<DrawerBody
212+
display="flex"
213+
flexDirection="column"
214+
h="100%"
215+
>
216+
<TableContainer
217+
flex="1"
218+
w="100%"
219+
border="1px"
220+
borderColor="gray.200"
221+
borderRadius="12px"
222+
overflowY="auto"
223+
>
224+
<Table variant="simple">
225+
<Tbody>
226+
<Tr>
227+
<Td fontSize="medium">Name</Td>
228+
<Td>
229+
<TextInputComponent
230+
name="name"
231+
type="text"
232+
value={`${newUser.firstName} ${newUser.lastName}`}
233+
onChange={handleChange}
234+
width="100%"
235+
/>
236+
</Td>
237+
</Tr>
238+
<Tr>
239+
<Td fontSize="medium">Email</Td>
240+
<Td>
241+
<TextInputComponent
242+
name="email"
243+
type="email"
244+
value={newUser.email}
245+
onChange={handleChange}
246+
width="100%"
247+
/>
248+
</Td>
249+
</Tr>
250+
<Tr>
251+
<Td fontSize="medium">Location</Td>
252+
<Td>
253+
<SelectInputComponent
254+
name="location"
255+
value={newUser.location}
256+
onChange={handleChange}
257+
options={locationOptions}
258+
width="100%"
259+
/>
260+
</Td>
261+
</Tr>
262+
<Tr>
263+
<Td fontSize="medium">Phone</Td>
264+
<Td>
265+
<TextInputComponent
266+
name="phoneNumber"
267+
type="number"
268+
value={newUser.phoneNumber}
269+
onChange={handleChange}
270+
width="100%"
271+
/>
272+
</Td>
273+
</Tr>
274+
<Tr>
275+
<Td fontSize="medium">Notes</Td>
276+
<Td>
277+
<TextInputComponent
278+
name="notes"
279+
type="text"
280+
value={newUser.notes}
281+
onChange={handleChange}
282+
width="100%"
283+
/>
284+
</Td>
285+
</Tr>
286+
</Tbody>
287+
</Table>
288+
</TableContainer>
289+
290+
<HStack
291+
mt={4}
292+
spacing={3}
293+
w="100%"
294+
justifyContent="flex-end"
295+
>
296+
<Button onClick={modalOnOpen}>Cancel</Button>
297+
<Button colorScheme="blue" onClick={submitUser} >Save</Button>
298+
</HStack>
299+
</DrawerBody>
300+
301+
<CancelAddModal
302+
isOpen={modalIsOpen}
303+
onClose={modalOnClose}
304+
title={title}
305+
onSubmit={onClose}
306+
/>
307+
</DrawerContent>
308+
</Drawer>
309+
);
310+
};
311+
312+
export default AddPreview;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
AlertDialog,
3+
AlertDialogBody,
4+
AlertDialogFooter,
5+
AlertDialogHeader,
6+
AlertDialogContent,
7+
AlertDialogOverlay,
8+
Button,
9+
Text,
10+
Flex,
11+
ModalCloseButton,
12+
} from "@chakra-ui/react";
13+
import { useRef } from "react";
14+
15+
interface ModalProps {
16+
isOpen: boolean;
17+
onClose: () => void;
18+
title: string;
19+
onSubmit: () => void | Promise<void>;
20+
}
21+
22+
export const CancelAddModal = ({ isOpen, onClose, title, onSubmit } : ModalProps) => {
23+
const cancelRef = useRef<HTMLButtonElement | null>(null);
24+
25+
return (
26+
<AlertDialog
27+
isOpen={isOpen}
28+
leastDestructiveRef={cancelRef}
29+
onClose={onClose}
30+
isCentered
31+
>
32+
<AlertDialogOverlay>
33+
<AlertDialogContent borderRadius="lg">
34+
<ModalCloseButton top={4} right={4} />
35+
36+
<AlertDialogHeader
37+
fontSize="xl"
38+
fontWeight="bold"
39+
display="flex"
40+
alignItems="center"
41+
gap={2}
42+
>
43+
Cancel Adding New {title}
44+
</AlertDialogHeader>
45+
46+
<AlertDialogBody>
47+
<Flex mb={3}>
48+
<Text>Are you sure? You can't undo this action afterwards.</Text>
49+
</Flex>
50+
</AlertDialogBody>
51+
52+
<AlertDialogFooter>
53+
<Button
54+
ref={cancelRef}
55+
onClick={onClose}
56+
bg="gray.100"
57+
_hover={{ bg: "gray.200" }}
58+
mr={3}
59+
px={8}
60+
py={6}
61+
fontWeight="bold"
62+
borderRadius="lg"
63+
>
64+
Cancel
65+
</Button>
66+
<Button
67+
colorScheme="blue"
68+
onClick={() => {
69+
onSubmit();
70+
onClose();
71+
}}
72+
px={8}
73+
py={6}
74+
fontWeight="bold"
75+
borderRadius="lg"
76+
>
77+
Yes
78+
</Button>
79+
</AlertDialogFooter>
80+
</AlertDialogContent>
81+
</AlertDialogOverlay>
82+
</AlertDialog>
83+
);
84+
}

0 commit comments

Comments
 (0)