Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project submission modal #451

Merged
merged 3 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions frontend/src/components/ConfirmationModal/ConfirmationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from 'react';
import { IoMdClose } from 'react-icons/io';

export interface ConfirmationModalProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
primaryAction: () => void;
primaryActionText?: string;
secondaryActionText?: string;
primaryButtonClassName?: string;
secondaryButtonClassName?: string;
showCloseButton?: boolean;
}

export const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
isOpen,
onClose,
title,
children,
primaryAction,
primaryActionText = 'Confirm',
secondaryActionText = 'Cancel',
primaryButtonClassName = '',
secondaryButtonClassName = '',
showCloseButton = true,
}) => {
return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-50" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black/25" aria-hidden="true" />
</Transition.Child>

<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative w-full max-w-md transform overflow-hidden rounded-lg bg-white p-6 text-left shadow-xl transition-all">
{showCloseButton && (
<button
onClick={onClose}
className="absolute right-4 top-4 rounded-lg p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500"
>
<IoMdClose className="h-5 w-5" />
</button>
)}

{title && (
<Dialog.Title className="text-2xl font-bold text-gray-900">
{title}
</Dialog.Title>
)}

<div className="mt-4 text-base text-gray-600">
{children}
</div>

<div className="mt-8 flex justify-end gap-3">
<button
type="button"
className={`rounded-lg border border-gray-300 bg-white px-4 py-2 text-gray-900 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${secondaryButtonClassName}`}
onClick={onClose}
>
{secondaryActionText}
</button>

<button
type="button"
className={`rounded-lg bg-gray-500 px-4 py-2 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${primaryButtonClassName}`}
onClick={primaryAction}
>
{primaryActionText}
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
};
2 changes: 2 additions & 0 deletions frontend/src/components/ConfirmationModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { ConfirmationModal } from './ConfirmationModal';
export type { ConfirmationModalProps } from './ConfirmationModal';
47 changes: 39 additions & 8 deletions frontend/src/pages/user/_auth/project/$projectId.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { SectionedLayout } from '@/templates';
import { cva } from 'class-variance-authority';
import { sanitizeHtmlId } from '@/utils/html';
import { QuestionInputs } from '@/components/QuestionInputs/QuestionInputs';
import { ConfirmationModal } from '@/components/ConfirmationModal';
import { useQuery } from '@tanstack/react-query';
import { scrollToTop } from '@/utils';
import { useDebounceFn } from '@/hooks';
Expand Down Expand Up @@ -75,6 +76,7 @@ function ProjectFormPage() {
const [currentStep, setCurrentStep] = useState<number>(0);
const dirtyInputRef = useRef<Map<string, ProjectDraft>>(new Map());
const notification = useNotification();
const [showSubmitModal, setShowSubmitModal] = useState(false);

const autosave = useDebounceFn(
async () => {
Expand Down Expand Up @@ -492,20 +494,33 @@ function ProjectFormPage() {
});

if (valid) {
try {
if (!accessToken || !currentProjectId) return;
await submitProject(accessToken, currentProjectId);
// replace to not let them go back, it causes the creation of a new project
navigate({ to: '/user/dashboard', replace: true });
} catch (e) {
console.error(e);
}
// try {
// if (!accessToken || !currentProjectId) return;
// await submitProject(accessToken, currentProjectId);
// // replace to not let them go back, it causes the creation of a new project
// navigate({ to: '/user/dashboard', replace: true });
// } catch (e) {
// console.error(e);
// }
setShowSubmitModal(true);
} else {
// update the group questions so that it refreshes the ui
setGroupedQuestions((prev) => [...prev]);
}
};

const handleSubmitConfirm = async () => {
try {
if (!accessToken || !currentProjectId) return;
await submitProject(accessToken, currentProjectId);

// replace to not let them go back, it causes the creation of a new project
navigate({ to: '/user/dashboard', replace: true });
} catch (e) {
console.error(e);
}
}

// TODO: make a better loading screen
if (groupedQuestions.length < 1 || loadingQuestions) return null;

Expand Down Expand Up @@ -650,6 +665,22 @@ function ProjectFormPage() {
</form>
</div>
</SectionedLayout>

<ConfirmationModal
isOpen={showSubmitModal}
onClose={() => setShowSubmitModal(false)}
primaryAction={handleSubmitConfirm}
title="Submit Application?"
primaryActionText="Yes, submit it"
>
<div className="space-y-4">
<p>Have you double-checked everything in this project?</p>
<p>
Once submitted, you won't be able to make changes until the application
is either approved or sent back for review.
</p>
</div>
</ConfirmationModal>
</div>
);
}
Loading