Skip to content

Commit 70db3c2

Browse files
Merge branch 'main' into colin/email-subs-list
2 parents 7437a20 + 33e0699 commit 70db3c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+632
-466
lines changed

.eslintrc.json

Lines changed: 0 additions & 14 deletions
This file was deleted.

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
- If you intend to contribute to this project ensure you have been added to the [UW Blueprint Github Organization](https://github.com/uwblueprint/).
1818
- Install [Node.js](https://nodejs.org/en/download/) (v22 tested). It's recommended to use [NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) to manage your Node.js versions.
1919
- Install Docker Desktop ([MacOS](https://docs.docker.com/desktop/setup/install/mac-install/) | [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Linux](https://docs.docker.com/desktop/setup/install/linux/)) and ensure that it is running.
20-
-
20+
-
21+
2122
## Clone and Install
2223

2324
- Clone the [Sistema Github Repository](https://github.com/uwblueprint/sistema) to your local machine and `cd` into the project folder:

eslint.config.mjs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FlatCompat } from '@eslint/eslintrc';
22
import js from '@eslint/js';
3-
import prettier from 'eslint-plugin-prettier';
3+
import tseslintPlugin from '@typescript-eslint/eslint-plugin';
4+
import tseslintParser from '@typescript-eslint/parser';
45
import path from 'node:path';
56
import { fileURLToPath } from 'node:url';
67

@@ -9,17 +10,11 @@ const __dirname = path.dirname(__filename);
910
const compat = new FlatCompat({
1011
baseDirectory: __dirname,
1112
recommendedConfig: js.configs.recommended,
12-
allConfig: js.configs.all,
1313
});
1414

1515
const eslintConfig = [
1616
...compat.config({
1717
extends: ['next', 'next/core-web-vitals', 'plugin:prettier/recommended'],
18-
settings: {
19-
plugins: {
20-
prettier,
21-
},
22-
},
2318
rules: {
2419
'prettier/prettier': [
2520
'error',
@@ -31,6 +26,22 @@ const eslintConfig = [
3126
},
3227
ignorePatterns: ['.next/'],
3328
}),
29+
{
30+
files: ['**/*.ts', '**/*.tsx'],
31+
languageOptions: {
32+
parser: tseslintParser,
33+
parserOptions: {
34+
project: ['./tsconfig.json'],
35+
tsconfigRootDir: __dirname,
36+
},
37+
},
38+
plugins: {
39+
'@typescript-eslint': tseslintPlugin,
40+
},
41+
rules: {
42+
'@typescript-eslint/no-unused-vars': ['error'],
43+
},
44+
},
3445
];
3546

3647
export default eslintConfig;

hooks/useChangeManagement.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ import { useCallback, useEffect, useState } from 'react';
1616
interface UseChangeManagementProps {
1717
subjects: SubjectAPI[];
1818
locations: Location[];
19-
colorGroups: { id: number; name: string; colorCodes: string[] }[];
2019
absenceCap: number;
2120
onRefresh?: () => void;
22-
toast?: any;
21+
showToast?: any;
2322
}
2423

2524
interface UseChangeManagementReturn {
@@ -41,10 +40,9 @@ interface UseChangeManagementReturn {
4140
export const useChangeManagement = ({
4241
subjects: initialSubjects,
4342
locations: initialLocations,
44-
colorGroups,
4543
absenceCap: initialAbsenceCap,
4644
onRefresh,
47-
toast,
45+
showToast,
4846
}: UseChangeManagementProps): UseChangeManagementReturn => {
4947
// Store maps of pending entity changes
5048
const [pendingSubjects, setPendingSubjects] = useState<
@@ -183,7 +181,7 @@ export const useChangeManagement = ({
183181
setPendingSettings((prev) => {
184182
// If new absence cap equals original, remove it from pending settings
185183
if (newAbsenceCap === initialAbsenceCap) {
186-
const { absenceCap, ...rest } = prev;
184+
const { ...rest } = prev;
187185
return rest;
188186
}
189187

@@ -398,12 +396,11 @@ export const useChangeManagement = ({
398396
}
399397

400398
// Show success toast
401-
if (toast) {
402-
toast({
399+
if (showToast) {
400+
showToast({
403401
title: 'Changes saved',
404402
status: 'success',
405403
duration: 3000,
406-
isClosable: true,
407404
});
408405
}
409406

@@ -418,13 +415,11 @@ export const useChangeManagement = ({
418415
}
419416

420417
// Show error toast if there was a problem
421-
if (!success && toast) {
422-
toast({
418+
if (!success && showToast) {
419+
showToast({
423420
title: 'Error',
424421
description: errorMessage || 'Failed to save changes',
425422
status: 'error',
426-
duration: 5000,
427-
isClosable: true,
428423
});
429424
}
430425

src/components/CustomToast.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
CheckCircleIcon,
3+
CloseIcon,
4+
InfoIcon,
5+
WarningIcon,
6+
} from '@chakra-ui/icons';
7+
import { Box, Text, useTheme, useToast } from '@chakra-ui/react';
8+
import { ReactNode } from 'react';
9+
10+
const iconMap = {
11+
success: CheckCircleIcon,
12+
warning: WarningIcon,
13+
error: CloseIcon,
14+
info: InfoIcon,
15+
};
16+
17+
const colorMap = (theme) => ({
18+
success: theme.colors.positiveGreen[200],
19+
warning: theme.colors.warningOrange[300],
20+
error: theme.colors.errorRed[200],
21+
info: theme.colors.primaryBlue[300],
22+
});
23+
24+
interface CustomToastProps {
25+
description?: string | ReactNode;
26+
status?: 'success' | 'warning' | 'error' | 'info';
27+
}
28+
29+
export const CustomToast: React.FC<CustomToastProps> = ({
30+
description,
31+
status = 'info',
32+
}) => {
33+
const theme = useTheme();
34+
const Icon = iconMap[status] || InfoIcon;
35+
const color = colorMap(theme)[status];
36+
37+
return (
38+
<Box
39+
bg="white"
40+
width="360px"
41+
border="1px solid"
42+
borderColor={color}
43+
borderRadius="md"
44+
px={3}
45+
py={3}
46+
display="flex"
47+
alignItems="center"
48+
boxShadow="md"
49+
>
50+
<Box mr={3} display="flex" alignItems="center">
51+
<Icon boxSize="30px" color={color} />
52+
</Box>
53+
<Box>
54+
{description &&
55+
(typeof description === 'string' ? (
56+
<Text fontSize="14px" color="black">
57+
{description}
58+
</Text>
59+
) : (
60+
<Box fontSize="14px" color="black">
61+
{description}
62+
</Box>
63+
))}
64+
</Box>
65+
</Box>
66+
);
67+
};
68+
69+
const allowedStatuses = ['success', 'warning', 'error', 'info'] as const;
70+
type ToastStatus = (typeof allowedStatuses)[number];
71+
72+
function isToastStatus(value: any): value is ToastStatus {
73+
return allowedStatuses.includes(value);
74+
}
75+
76+
export const useCustomToast = () => {
77+
const toast = useToast();
78+
79+
return ({
80+
description,
81+
status = 'info',
82+
}: {
83+
title?: string;
84+
description?: string | ReactNode;
85+
status?: string;
86+
}) => {
87+
const safeStatus: ToastStatus = isToastStatus(status) ? status : 'info';
88+
89+
toast({
90+
isClosable: true,
91+
position: 'bottom-left',
92+
render: () => (
93+
<CustomToast description={description} status={safeStatus} />
94+
),
95+
});
96+
};
97+
};
File renamed without changes.
File renamed without changes.
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Box, Image, Input, Text, useToast } from '@chakra-ui/react';
1+
import { Box, Image, Input, Text } from '@chakra-ui/react';
22
import { LessonPlanFile } from '@utils/types';
33
import { useRef, useState } from 'react';
4+
import { useCustomToast } from '../CustomToast';
45

56
interface FileUploadProps {
67
lessonPlan: File | null;
@@ -17,18 +18,15 @@ export const FileUpload: React.FC<FileUploadProps> = ({
1718
}) => {
1819
const [isDragging, setIsDragging] = useState(false);
1920
const inputRef = useRef<HTMLInputElement>(null);
20-
const toast = useToast();
21+
const showToast = useCustomToast();
2122

2223
const validateAndSetFile = (file: File) => {
2324
if (file.type === 'application/pdf' || file.name.endsWith('.pdf')) {
2425
setLessonPlan(file);
2526
} else {
26-
toast({
27-
title: 'Invalid File Type',
27+
showToast({
2828
description: 'Please upload a valid PDF file.',
2929
status: 'error',
30-
duration: 5000,
31-
isClosable: true,
3230
});
3331
}
3432
};

src/components/absences/declare/ConfirmAbsenceModal.tsx

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)