fix: improve dialog handling and error management in list items (#257)
* fix: improve dialog handling and error management in list items * chore: lint
This commit is contained in:
@@ -100,6 +100,12 @@ module.exports = {
|
|||||||
'import/no-cycle': 'off',
|
'import/no-cycle': 'off',
|
||||||
'import/no-extraneous-dependencies': 'off',
|
'import/no-extraneous-dependencies': 'off',
|
||||||
'react/jsx-props-no-spreading': 'off',
|
'react/jsx-props-no-spreading': 'off',
|
||||||
|
'react/jsx-no-useless-fragment': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowExpressions: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
'keyword-spacing': [
|
'keyword-spacing': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type TabInfoMessages from '@shared/messages/TabInfoMessages';
|
import type TabInfoMessages from '@shared/messages/TabInfoMessages';
|
||||||
import Calendar from '@views/components/calendar/Calendar';
|
import Calendar from '@views/components/calendar/Calendar';
|
||||||
|
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
||||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||||
import { MessageListener } from 'chrome-extension-toolkit';
|
import { MessageListener } from 'chrome-extension-toolkit';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
@@ -26,7 +27,9 @@ export default function CalendarMain() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ExtensionRoot className='h-full w-full'>
|
<ExtensionRoot className='h-full w-full'>
|
||||||
<Calendar />
|
<DialogProvider>
|
||||||
|
<Calendar />
|
||||||
|
</DialogProvider>
|
||||||
</ExtensionRoot>
|
</ExtensionRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export default function PopupMain(): JSX.Element {
|
|||||||
</ScheduleDropdown>
|
</ScheduleDropdown>
|
||||||
</div>
|
</div>
|
||||||
{activeSchedule?.courses?.length === 0 && (
|
{activeSchedule?.courses?.length === 0 && (
|
||||||
<div className='flex flex-col items-center self-center gap-1.25 px-2 py-2 max-w-64'>
|
<div className='max-w-64 flex flex-col items-center self-center gap-1.25 px-2 py-2'>
|
||||||
<Text variant='small' className='text-center text-ut-gray !font-normal'>
|
<Text variant='small' className='text-center text-ut-gray !font-normal'>
|
||||||
{funny}
|
{funny}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ export default function DialogProvider(props: { children: ReactNode }): JSX.Elem
|
|||||||
key={id}
|
key={id}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
afterLeave={onLeave}
|
afterLeave={onLeave}
|
||||||
title={infoUnwrapped.title}
|
title=<>{infoUnwrapped.title}</>
|
||||||
description={infoUnwrapped.description}
|
description=<>{infoUnwrapped.description}</>
|
||||||
appear
|
appear
|
||||||
show={show}
|
show={show}
|
||||||
className={infoUnwrapped.className}
|
className={infoUnwrapped.className}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import XIcon from '~icons/material-symbols/close';
|
|||||||
import DragIndicatorIcon from '~icons/material-symbols/drag-indicator';
|
import DragIndicatorIcon from '~icons/material-symbols/drag-indicator';
|
||||||
|
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import PromptDialog from './Prompt';
|
import { usePrompt } from './DialogProvider/DialogProvider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Props for the ScheduleListItem component.
|
* Props for the ScheduleListItem component.
|
||||||
@@ -31,6 +31,8 @@ export default function ScheduleListItem({ schedule, dragHandleProps, onClick }:
|
|||||||
const [editorValue, setEditorValue] = useState(schedule.name);
|
const [editorValue, setEditorValue] = useState(schedule.name);
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
|
const showDialog = usePrompt();
|
||||||
|
|
||||||
const editorRef = React.useRef<HTMLInputElement>(null);
|
const editorRef = React.useRef<HTMLInputElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
@@ -58,24 +60,25 @@ export default function ScheduleListItem({ schedule, dragHandleProps, onClick }:
|
|||||||
deleteSchedule(schedule.id).catch(e => setError(e.message));
|
deleteSchedule(schedule.id).catch(e => setError(e.message));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
showDialog({
|
||||||
|
title: <span className='text-ut-red'>Something went wrong.</span>,
|
||||||
|
description: error,
|
||||||
|
// eslint-disable-next-line react/no-unstable-nested-components
|
||||||
|
buttons: close => (
|
||||||
|
<Button variant='filled' color='ut-black' onClick={close}>
|
||||||
|
I understand
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
onClose: () => setError(undefined),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='rounded bg-white'>
|
<div className='rounded bg-white'>
|
||||||
<PromptDialog
|
|
||||||
isOpen={!!error}
|
|
||||||
onClose={() => setError(undefined)}
|
|
||||||
title={
|
|
||||||
<Text className='text-red' variant='h4'>
|
|
||||||
Something Went Wrong
|
|
||||||
</Text>
|
|
||||||
}
|
|
||||||
content={<Text variant='p'>{error}</Text>}
|
|
||||||
// eslint-disable-next-line react/no-children-prop
|
|
||||||
children={[
|
|
||||||
<Button key='yes' variant='filled' color='ut-black' onClick={() => setError(undefined)}>
|
|
||||||
I understand
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<li className='w-full flex cursor-pointer items-center text-ut-burntorange'>
|
<li className='w-full flex cursor-pointer items-center text-ut-burntorange'>
|
||||||
<div className='h-full cursor-move focusable' {...dragHandleProps}>
|
<div className='h-full cursor-move focusable' {...dragHandleProps}>
|
||||||
<DragIndicatorIcon className='h-6 w-6 cursor-move text-zinc-300 btn-transition -ml-1.5 hover:text-zinc-400' />
|
<DragIndicatorIcon className='h-6 w-6 cursor-move text-zinc-300 btn-transition -ml-1.5 hover:text-zinc-400' />
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ export type CloseWrapper<T> = (close: () => void) => T;
|
|||||||
* Information about a dialog.
|
* Information about a dialog.
|
||||||
*/
|
*/
|
||||||
export interface DialogInfo {
|
export interface DialogInfo {
|
||||||
title?: JSX.Element;
|
title?: string | JSX.Element;
|
||||||
description?: JSX.Element;
|
description?: string | JSX.Element;
|
||||||
className?: string;
|
className?: string;
|
||||||
buttons?: JSX.Element | CloseWrapper<JSX.Element>;
|
buttons?: JSX.Element | CloseWrapper<JSX.Element>;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
@@ -24,7 +24,9 @@ export type ShowDialogFn = (info: DialogInfo | CloseWrapper<DialogInfo>) => void
|
|||||||
/**
|
/**
|
||||||
* Context for the dialog provider.
|
* Context for the dialog provider.
|
||||||
*/
|
*/
|
||||||
export const DialogContext = createContext<ShowDialogFn>(() => {});
|
export const DialogContext = createContext<ShowDialogFn>(() => {
|
||||||
|
throw new Error('DialogContext not initialized.');
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns The dialog context for showing dialogs.
|
* @returns The dialog context for showing dialogs.
|
||||||
|
|||||||
Reference in New Issue
Block a user