Skip to content

Commit

Permalink
Feat: added identification hook and form
Browse files Browse the repository at this point in the history
  • Loading branch information
Akalanka47000 committed Oct 12, 2023
1 parent 0af7144 commit b0b70f9
Show file tree
Hide file tree
Showing 14 changed files with 295 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ VITE_BASHAWAY_BE_URL=https://api.staging.bashaway.sliitfoss.org
VITE_FIREBASE_CONFIG=
VITE_AZURE_UPLOAD_SAS_TOKEN=
VITE_AZURE_DOWNLOAD_SAS_TOKEN=
VITE_AZURE_GENERIC_UPLOAD_SAS_TOKEN=
VITE_AZURE_STORAGE_ACCOUNT=
VITE_AZURE_GENERIC_STORAGE_ACCOUNT=
VITE_AZURE_STORAGE_CONTAINER=
VITE_APP_ENV=local
VITE_SENTRY_DSN=
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/preview-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ jobs:
VITE_FIREBASE_CONFIG: ${{ secrets.STAGING_FIREBASE_CONFIG }}
VITE_AZURE_UPLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_UPLOAD_SAS_TOKEN }}
VITE_AZURE_DOWNLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_DOWNLOAD_SAS_TOKEN }}
VITE_AZURE_GENERIC_UPLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_GENERIC_UPLOAD_SAS_TOKEN }}
VITE_AZURE_STORAGE_ACCOUNT: ${{ secrets.STAGING_AZURE_STORAGE_ACCOUNT }}
VITE_AZURE_GENERIC_STORAGE_ACCOUNT: ${{ secrets.STAGING_AZURE_GENERIC_STORAGE_ACCOUNT }}
VITE_AZURE_STORAGE_CONTAINER: ${{ secrets.STAGING_AZURE_STORAGE_CONTAINER }}
VITE_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
VITE_APP_ENV: staging
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/staging-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ jobs:
VITE_FIREBASE_CONFIG: ${{ secrets.STAGING_FIREBASE_CONFIG }}
VITE_AZURE_UPLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_UPLOAD_SAS_TOKEN }}
VITE_AZURE_DOWNLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_DOWNLOAD_SAS_TOKEN }}
VITE_AZURE_GENERIC_UPLOAD_SAS_TOKEN: ${{ secrets.STAGING_AZURE_GENERIC_UPLOAD_SAS_TOKEN }}
VITE_AZURE_STORAGE_ACCOUNT: ${{ secrets.STAGING_AZURE_STORAGE_ACCOUNT }}
VITE_AZURE_GENERIC_STORAGE_ACCOUNT: ${{ secrets.STAGING_AZURE_GENERIC_STORAGE_ACCOUNT }}
VITE_AZURE_STORAGE_CONTAINER: ${{ secrets.STAGING_AZURE_STORAGE_CONTAINER }}
VITE_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
VITE_APP_ENV: staging
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@azure/storage-blob": "12.15.0",
"@reduxjs/toolkit": "1.9.5",
"@sentry/react": "7.69.0",
"@sliit-foss/bashaway-ui": "0.5.4",
"@sliit-foss/bashaway-ui": "0.7.3",
"async-mutex": "^0.4.0",
"firebase": "10.2.0",
"framer-motion": "10.14.0",
Expand Down
80 changes: 76 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/app.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Provider } from "react-redux";
import { useLocation } from "react-router-dom";
import { motion } from "framer-motion";
import { Footer, Header } from "@/components";
import { Footer, Header, IdentificationForm } from "@/components";
import { useAuth } from "@/hooks";
import { default as AnimatedRoutes } from "@/routes";
import { store } from "@/store";
Expand All @@ -28,6 +28,7 @@ const App = () => {
<Footer />
<Loader />
<Toaster />
<IdentificationForm />
<div
className={`fixed inset-0 h-screen w-full bg-white z-50 transition-all duration-long ${
completed ? "opacity-0 pointer-events-none" : "opacity-100"
Expand Down
147 changes: 147 additions & 0 deletions src/components/identification-form.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { useEffect, useState } from "react";
import { Paperclip } from "lucide-react";
import { useSelector } from "react-redux";
import { store } from "@/store";
import { authApi, useAuthUserQuery, useUpdateProfileMutation } from "@/store/api";
import { toggleIdentificationForm } from "@/store/reducers/ui/global";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
AlertDialog,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
Button,
Dropdown,
Input,
toast
} from "@sliit-foss/bashaway-ui/components";
import { gender, mealPreference } from "@sliit-foss/bashaway-ui/constants";

const close = () => store.dispatch(toggleIdentificationForm(false));

const IdentificationForm = () => {
const open = useSelector((store) => store.ui.global.showIdentificationForm);

const { data: { data: team } = {} } = useAuthUserQuery();

const [updateProfile, { isLoading }] = useUpdateProfileMutation();

const [formData, setFormData] = useState(team?.members);
const [idFiles, setIdFiles] = useState([]);

useEffect(() => {
if (team) setFormData(team.members);
}, [team]);

const handleSubmit = async () => {
await updateProfile({
id: team._id,
data: {
members: formData
}
})
.unwrap()
.then((data) => {
store.dispatch(authApi.util.upsertQueryData("authUser", undefined, { data: data?.data }));
close();
toast({ title: "Details recorded successfully" });
});
};

const onFileChange = (e, index) => {
setIdFiles((prev) => {
const newFiles = JSON.parse(JSON.stringify(prev));
newFiles[index] = e.target.files[0];
return newFiles;
});
};

const onChange = (e, index) => {
const newFormData = JSON.parse(JSON.stringify(formData));
newFormData[index][e.target.name] = e.target.value;
setFormData(newFormData);
};

return (
<AlertDialog
open={open}
onOpenChange={(open) => {
if (!open) close();
}}
>
<AlertDialogContent>
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
<AlertDialogHeader>
<AlertDialogTitle>Hello there!</AlertDialogTitle>
<AlertDialogDescription>
Congratulations on being selected to the final round of Bashaway 2023. However, before you can continue to
use this platform to compete further, please fill in the following details.
</AlertDialogDescription>
</AlertDialogHeader>
<Accordion type="single" collapsible>
{formData?.map((member, index) => (
<AccordionItem key={index} value={`member-${index}`}>
<AccordionTrigger>{member.name}</AccordionTrigger>
<AccordionContent containerClassName="flex flex-col gap-3">
<Input
placeholder="NIC *"
name="nic"
required
className="sm:h-14"
onChange={(e) => onChange(e, index)}
/>
<div className="flex flex-col md:flex-row gap-3">
<Dropdown
filterkey="gender"
label="Gender *"
options={gender.options}
className="sm:h-14"
value={formData[index].gender}
onChange={(e) => onChange(e, index)}
/>
<Dropdown
filterkey="meal_preference"
label="Meal Preference *"
options={mealPreference.options}
className="sm:h-14"
value={formData[index].meal_preference}
onChange={(e) => onChange(e, index)}
/>
</div>
<Input
placeholder="University ID (both sides) *"
name="student_id_url"
value={idFiles[index] ? idFiles[index].name : formData.student_id_url}
required
className="sm:h-14 cursor-pointer"
onClick={() => document.getElementById(`id-upload-${index}`).click()}
suffixIcon={<Paperclip className="text-gray-400 pointer-events-none" size={21} />}
readOnly
/>
<input
id={`id-upload-${index}`}
type="file"
className="hidden"
onChange={(e) => onFileChange(e, index)}
/>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
<AlertDialogFooter className="mt-4">
<Button type="submit" loading={isLoading}>
Submit and continue
</Button>
</AlertDialogFooter>
</form>
</AlertDialogContent>
</AlertDialog>
);
};

export default IdentificationForm;
2 changes: 2 additions & 0 deletions src/components/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export * from "./layout";
export * from "./question-details";
export * from "./register";
export * from "./submissions";

export { default as IdentificationForm } from "./identification-form";
27 changes: 27 additions & 0 deletions src/hooks/identification.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useEffect } from "react";
import { useSelector } from "react-redux";
import { store } from "@/store";
import { useAuthUserQuery, useGetSettingsQuery } from "@/store/api";
import { toggleIdentificationForm } from "@/store/reducers/ui/global";

const useIdentification = () => {
const { data: { data: settings } = {} } = useGetSettingsQuery();
const { data: { data: team } = {} } = useAuthUserQuery();

const open = useSelector((store) => store.ui.global.showIdentificationForm);

useEffect(() => {
if (
team &&
settings?.round_breakpoint &&
new Date() > new Date(settings?.round_breakpoint) &&
!team.eliminated &&
team.members.find((member) => !member.nic) &&
!open
) {
store.dispatch(toggleIdentificationForm(true));
}
}, [settings]);
};

export default useIdentification;
1 change: 1 addition & 0 deletions src/hooks/index.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as useAuth } from "./auth";
export { default as useBreakpoint } from "./breakpoint";
export { default as useEffectOnce } from "./effect-once";
export { default as useIdentification } from "./identification";
export { default as useTitle } from "./title";
4 changes: 2 additions & 2 deletions src/pages/question-details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { default as startCase } from "lodash/startCase";
import { twMerge } from "tailwind-merge";
import { ActionButtons } from "@/components/question-details";
import { useEffectOnce, useTitle } from "@/hooks";
import { tracker, uploadFile } from "@/services";
import { tracker, uploadSubmission } from "@/services";
import { store } from "@/store";
import {
selectQuestionById,
Expand Down Expand Up @@ -42,7 +42,7 @@ export default function QuestionDetails() {
return toast({ variant: "destructive", title: "Submission size should be less than 25MB" });
if (!["zip"].includes(file.name?.split(".").pop()))
return toast({ variant: "destructive", title: "Submission should be a zip archive" });
const url = await uploadFile(file);
const url = await uploadSubmission(file);
await addSubmission({ question: id, link: url })
.unwrap()
.then(() => {
Expand Down
2 changes: 2 additions & 0 deletions src/routes/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Route, Routes, useLocation } from "react-router-dom";
import { AnimatePresence } from "framer-motion";
import { useIdentification } from "@/hooks";
import {
ChangePassword,
ForgotPassword,
Expand All @@ -15,6 +16,7 @@ import {

const AnimatedRoutes = () => {
const location = useLocation();
useIdentification();
return (
<AnimatePresence>
<Routes location={location}>
Expand Down
Loading

0 comments on commit b0b70f9

Please sign in to comment.