diff --git a/package-lock.json b/package-lock.json index 116303c..0a75b85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,18 @@ "name": "quizcreator", "version": "0.1.0", "dependencies": { + "@heroicons/react": "^2.0.18", "@types/react-select": "^5.0.1", "cross-env": "^7.0.3", "eslint": "8.44.0", "eslint-config-next": "13.4.9", + "feather-icons-react": "^0.6.2", "next": "13.4.9", "pre-commit": "^1.2.2", "react": "18.2.0", "react-dom": "18.2.0", + "react-feather": "^2.0.10", + "react-hook-form": "^7.45.4", "react-select": "^5.7.4", "typescript": "^5.1.6" }, @@ -355,6 +359,14 @@ "@floating-ui/core": "^1.3.1" } }, + "node_modules/@heroicons/react": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz", + "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==", + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -2175,6 +2187,14 @@ "reusify": "^1.0.4" } }, + "node_modules/feather-icons-react": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/feather-icons-react/-/feather-icons-react-0.6.2.tgz", + "integrity": "sha512-G677Y5nc3HzP1f5NNb5LJuZwKrI58BK4+/9O8Bl4naF9JixC+YL4trVom1F2ajnilq/EbU8JETPTNqvCzwH1qA==", + "peerDependencies": { + "react": ">= 16.8.4" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3835,6 +3855,32 @@ "react": "^18.2.0" } }, + "node_modules/react-feather": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz", + "integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/react-hook-form": { + "version": "7.45.4", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.45.4.tgz", + "integrity": "sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ==", + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index e212fda..e17b9a3 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "format": "npx prettier --write ." }, "dependencies": { + "@heroicons/react": "^2.0.18", "@types/react-select": "^5.0.1", "cross-env": "^7.0.3", "eslint": "8.44.0", @@ -20,6 +21,8 @@ "pre-commit": "^1.2.2", "react": "18.2.0", "react-dom": "18.2.0", + "react-feather": "^2.0.10", + "react-hook-form": "^7.45.4", "react-select": "^5.7.4", "typescript": "^5.1.6" }, diff --git a/src/components/Options/StudentDetailsOptions.tsx b/src/components/Options/StudentDetailsOptions.tsx index 894b518..572c069 100644 --- a/src/components/Options/StudentDetailsOptions.tsx +++ b/src/components/Options/StudentDetailsOptions.tsx @@ -1,7 +1,7 @@ -export type OptionType = { - value: string; +export interface OptionType { + value: string | boolean; label: string; -}; +} const ProgramOptions: OptionType[] = [ { value: "Haryana Students", label: "Haryana Students" }, @@ -174,10 +174,10 @@ const TestTakersOptions = [ ]; export { - ProgramOptions, - GradeOptions, + BatchOptions, CourseOptions, + GradeOptions, + ProgramOptions, StreamOptions, TestTakersOptions, - BatchOptions, }; diff --git a/src/components/Options/TestDetailsOptions.tsx b/src/components/Options/TestDetailsOptions.tsx index 5c2fbbb..7d4ff1c 100644 --- a/src/components/Options/TestDetailsOptions.tsx +++ b/src/components/Options/TestDetailsOptions.tsx @@ -1,7 +1,4 @@ -export type OptionType = { - value: string; - label: string; -}; +import { OptionType } from "./StudentDetailsOptions"; const TestTypeOptions: OptionType[] = [ { value: "assessment", label: "Assessment" }, @@ -44,9 +41,9 @@ const OptionalLimitOptions: OptionType[] = [ export { MarkingSchemeOptions, + OptionalLimitOptions, TestFormatOptions, - TestPurposeOptions, TestPlatformOptions, + TestPurposeOptions, TestTypeOptions, - OptionalLimitOptions, }; diff --git a/src/components/Options/TimelineOptions.tsx b/src/components/Options/TimelineOptions.tsx index 0afa374..220a135 100644 --- a/src/components/Options/TimelineOptions.tsx +++ b/src/components/Options/TimelineOptions.tsx @@ -1,16 +1,18 @@ -const IsEnabledOptions = [ +import { OptionType } from "./StudentDetailsOptions"; + +const IsEnabledOptions: OptionType[] = [ { value: true, label: "ON" }, { value: false, label: "OFF" }, ]; -const HasSyncedOptions = [ +const HasSyncedOptions: OptionType[] = [ { value: true, label: "TRUE" }, { value: false, label: "FALSE" }, ]; -const SessionTypeOptions = [ +const SessionTypeOptions: OptionType[] = [ { value: "infinite", label: "Infinite" }, { value: "standard", label: "Standard" }, ]; -export { IsEnabledOptions, HasSyncedOptions, SessionTypeOptions }; +export { HasSyncedOptions, IsEnabledOptions, SessionTypeOptions }; diff --git a/src/components/Stepper.tsx b/src/components/Stepper.tsx index eb6d2dd..0b8f535 100644 --- a/src/components/Stepper.tsx +++ b/src/components/Stepper.tsx @@ -1,40 +1,33 @@ -// Stepper.js -import { Step } from "@/pages/SessionCreator"; -import React from "react"; - -//Navigates throught different sub-pages by passing the current step and the active step and renders the components based on the sub-page user is presented at export default function Stepper({ steps, activeStep, }: { - steps: Step[]; + steps: string[]; activeStep: string; }) { return ( - <> -
    - {steps.map((step, index) => ( -
  1. + {steps.map((step, index) => ( +
  2. + - - {index + 1} - - -

    - {step} -

    -
    -
  3. - ))} -
- + {index + 1} + + +

+ {step} +

+
+ + ))} + ); } diff --git a/src/components/Steps/Form/SelectedField.tsx b/src/components/Steps/Form/SelectedField.tsx new file mode 100644 index 0000000..dcc27ae --- /dev/null +++ b/src/components/Steps/Form/SelectedField.tsx @@ -0,0 +1,39 @@ +import styles from "@/styles/Home.module.css"; +import { MyForm, MyFormKey } from "@/types/FormTypes"; +import { OptionType } from "@/types/types"; +import { Control, Controller } from "react-hook-form"; +import Select from "react-select"; +interface SelectFieldProps { + control: Control; + options: OptionType[]; + name_: MyFormKey; + placeholder?: string; +} + +const SelectField = ({ + control, + options, + name_, + placeholder, +}: SelectFieldProps) => { + return ( + ( + setSelectedProgram(selectedOption)} - instanceId="programSelect" - isSearchable - placeholder="Program" - /> - setSelectedGrade(selectedOption)} - instanceId="gradeSelect" - isSearchable - placeholder="Grade" - /> - setSelectedStream(selectedOption)} - instanceId="streamSelect" - isSearchable - placeholder="Stream" - /> - +
+
+ + + + + + - - -
- + + + ); } diff --git a/src/components/Steps/TestDetails.tsx b/src/components/Steps/TestDetails.tsx index 18a4168..3db4bba 100644 --- a/src/components/Steps/TestDetails.tsx +++ b/src/components/Steps/TestDetails.tsx @@ -1,117 +1,116 @@ -import React, { useState } from "react"; import styles from "../../styles/Home.module.css"; -import Select from "react-select"; +import { Step } from "@/pages/SessionCreator"; +import { MyForm } from "@/types/FormTypes"; +import { ActiveFormProps } from "@/types/types"; +import { SubmitHandler, useForm } from "react-hook-form"; import { MarkingSchemeOptions, + OptionalLimitOptions, TestFormatOptions, TestPlatformOptions, TestPurposeOptions, TestTypeOptions, - OptionalLimitOptions, } from "../Options/TestDetailsOptions"; +import SelectField from "./Form/SelectedField"; // Renders sub-page containing test details -export default function TestDetails({ setActiveStep }) { - const [selectedTestType, setSelectedTestType] = useState(null); - const [selectedTestFormat, setSelectedTestFormat] = useState(null); - const [selectedTestPurpose, setSelectedTestPurpose] = useState(null); - const [selectedTestPlatform, setSelectedTestPlatform] = useState(null); - const [selectedMarkingScheme, setSelectedMarkingScheme] = useState(null); - const [selectedOptionalLimit, setSelectedOptionalLimit] = useState(null); +export function TestDetails({ data, setActiveStep, setData }: ActiveFormProps) { + const { register, handleSubmit, control } = useForm({ + defaultValues: { ...data.test }, + }); + + const onSubmit: SubmitHandler = (test) => { + setData((prevData) => ({ ...prevData, test })); + + setActiveStep(Step.TIMELINE); + }; return ( <>
-
- - + + setSelectedTestType(selectedOption)} - instanceId="test_typeSelect" - isSearchable placeholder="Test Type" /> - - setSelectedTestPurpose(selectedOption) - } - instanceId="test_purposeSelect" - isSearchable placeholder="Test Purpose" /> - + - setSelectedOptionalLimit(selectedOption) - } - instanceId="Optional_limitSelect" - isSearchable placeholder="Optional Limit" /> - - + +
diff --git a/src/components/Steps/Timeline.tsx b/src/components/Steps/Timeline.tsx index 23e939d..1fbf77d 100644 --- a/src/components/Steps/Timeline.tsx +++ b/src/components/Steps/Timeline.tsx @@ -1,114 +1,121 @@ -import { useRouter } from "next/router"; -import React, { useState } from "react"; -import styles from "../../styles/Home.module.css"; - -import Select from "react-select"; +import { Step } from "@/pages/SessionCreator"; +import { MyForm } from "@/types/FormTypes"; +import { ActiveFormProps } from "@/types/types"; +import { SubmitHandler, useForm } from "react-hook-form"; import { HasSyncedOptions, - SessionTypeOptions, IsEnabledOptions, + SessionTypeOptions, } from "../Options/TimelineOptions"; -//Renders the sub-page containing details of Session Timeline -export default function Timeline({ setActiveStep }) { - const router = useRouter(); - const [selectedSynced, setSelectedSynced] = useState(null); - const [selectedIsEnabled, setSelectedIsEnabled] = useState(null); - const [selectedSessionType, setSelectedSessionType] = useState(null); - useState(null); +import SelectField from "./Form/SelectedField"; - return ( - <> -
- -
-
-

Start Date

- -

End Date

- -
-
+export default function Timeline({ + data, + setActiveStep, + setData, + createSession, +}: ActiveFormProps) { + const { register, handleSubmit, control, reset } = useForm({ + defaultValues: { ...data.timeline }, + }); + + const onSubmit: SubmitHandler = (timeline) => { + setData((prevData) => ({ ...prevData, timeline })); + createSession!(); + reset(); + }; -
-

Start Time

+ return ( +
+ +
+
+ -

End Time

+
- - setSelectedSessionType(selectedOption) - } - instanceId="session_typeSelect" - isSearchable - placeholder="Sessions Type" - /> - +

End Time

+
-
- - -
- -
- + + + + + + +
+ + +
+ +
); } diff --git a/src/components/displayTable/DataDisplay.tsx b/src/components/displayTable/DataDisplay.tsx new file mode 100644 index 0000000..d641350 --- /dev/null +++ b/src/components/displayTable/DataDisplay.tsx @@ -0,0 +1,33 @@ +import { RowType } from "@/types/types"; +import TableRow from "./Row"; + +const DataDisplay = ({ data }: { data: RowType[] }) => { + return ( +
+
+ + + + + + + + + + + + + + + + {data.map((row, i) => ( + + ))} + +
S.NoBatchTest NameStart DateEnd DateTest TakerReport LinkTest LinkActions
+
+
+ ); +}; + +export default DataDisplay; diff --git a/src/components/displayTable/Row.tsx b/src/components/displayTable/Row.tsx new file mode 100644 index 0000000..f75843f --- /dev/null +++ b/src/components/displayTable/Row.tsx @@ -0,0 +1,56 @@ +import { RowType } from "@/types/types"; +import { useState } from "react"; +import { Copy, Edit, Trash2 } from "react-feather"; + +const TableRow = ({ row, index }: { row: RowType; index: number }) => { + const [isExpand, setIsExpand] = useState(false); + const { + student: { batch, testTakers }, + test: { name, sessionLink }, + timeline: { reportLink, startDate, endDate }, + } = row!; + + return ( + <> + setIsExpand(!isExpand)}> + {index} + {batch} + {name} + {startDate} + {endDate} + {testTakers} + {reportLink} + {sessionLink} + + { + e.stopPropagation(); + }} + /> + { + e.stopPropagation(); + }} + /> + { + e.stopPropagation(); + }} + /> + + + + {/* Collapsible Container */} + {isExpand && ( + + Helllo world + + )} + + ); +}; + +export default TableRow; diff --git a/src/pages/SessionCreator.tsx b/src/pages/SessionCreator.tsx index 591a4ee..56d9afd 100644 --- a/src/pages/SessionCreator.tsx +++ b/src/pages/SessionCreator.tsx @@ -1,29 +1,66 @@ import Stepper from "@/components/Stepper"; -import TestDetails from "@/components/Steps/TestDetails"; -import Timeline from "@/components/Steps/Timeline"; import StudentDetails from "@/components/Steps/StudentDetails"; +import { TestDetails } from "@/components/Steps/TestDetails"; +import Timeline from "@/components/Steps/Timeline"; +import { RowType } from "@/types/types"; +import { useRouter } from "next/router"; + +import { useState } from "react"; -import React, { useState } from "react"; export enum Step { STUDENT_DETAILS = "StudentDetails", TEST_DETAILS = "TestDetails", TIMELINE = "Timeline", } -//Renders the main page for the multiple sub-pages that are rendered after +const stepArr: string[] = [ + Step.STUDENT_DETAILS, + Step.TEST_DETAILS, + Step.TIMELINE, +]; + export default function SessionCreator() { + const router = useRouter(); const [activeStep, setActiveStep] = useState(Step.STUDENT_DETAILS); + const [data, setData] = useState({ + student: {}, + test: {}, + timeline: {}, + }); + + const createSession = () => { + // TODO: POST DATA FUNCTION HERE + // setTimeout(() => router.push('/'), 2000); + }; const activeForm = () => { if (activeStep === Step.STUDENT_DETAILS) { - return ; + return ( + + ); } else if (activeStep === Step.TEST_DETAILS) { - return ; + return ( + + ); } else { - return ; + return ( + + ); } }; - const steps = [Step.STUDENT_DETAILS, Step.TEST_DETAILS, Step.TIMELINE]; return ( <>
@@ -31,7 +68,7 @@ export default function SessionCreator() {
Created Date: 26-06-2023
Created By: Arya Jain
- + {activeForm()} ); diff --git a/src/pages/SessionInfo.tsx b/src/pages/SessionInfo.tsx deleted file mode 100644 index f03122c..0000000 --- a/src/pages/SessionInfo.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import Button from "@/components/Buttons/Button"; -import { useRouter } from "next/navigation"; -import React from "react"; - -// Renders the Information of the latest session Created -export default function SessionInfo() { - const router = useRouter(); - const handleCreateSession = () => { - router.push("/SessionCreator"); - }; - return ( - <> -
-
-
- - -
- - ); -} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a2c24d0..ffcd772 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,9 +1,15 @@ +import DataDisplay from "@/components/displayTable/DataDisplay"; +import { data } from "@/utils/data"; +// import { Inter } from "next/font/google"; import Head from "next/head"; -import { Inter } from "next/font/google"; -import SessionInfo from "./SessionInfo"; -const inter = Inter({ subsets: ["latin"] }); +import { useRouter } from "next/router"; +// const inter = Inter({ subsets: ["latin"] }); + +// TODO: Fetch data from the server using axios export default function Home() { + const router = useRouter(); + return ( <> @@ -11,7 +17,22 @@ export default function Home() { - + + + + ); } diff --git a/src/types/FormTypes.ts b/src/types/FormTypes.ts new file mode 100644 index 0000000..230c558 --- /dev/null +++ b/src/types/FormTypes.ts @@ -0,0 +1,40 @@ +type StudentForm = { + program: string; + batch: string; + grade: string; + course: string; + stream: string; + testTakers: number; +}; + +type TestForm = { + name: string; + type: string; + format: string; + purpose: string; + platform: string; + markingScheme: string; + optionalLimit: string; + link: string; + id: string; + sessionId: string; + sessionLink: string; + cmsId: string; +}; + +type TimelineForm = { + isEnabled: string; + synced: string; + sessionType: string; + reportLink: string; + reportSchedule: string; + startDate: string; + endDate: string; + startTime: string; + endTime: string; +}; + +type MyForm = StudentForm | TestForm | TimelineForm; +type MyFormKey = keyof StudentForm | keyof TestForm | keyof TimelineForm; + +export type { MyForm, MyFormKey }; diff --git a/src/types/types.ts b/src/types/types.ts new file mode 100644 index 0000000..60d2dc4 --- /dev/null +++ b/src/types/types.ts @@ -0,0 +1,27 @@ +import { Dispatch, SetStateAction } from "react"; + +interface OptionType { + value: string | boolean; + label: string; +} + +interface ActiveFormProps { + data: RowType; + setActiveStep: Dispatch>; + setData: Dispatch>; + createSession?: () => void; +} + +interface RowType { + student: { + [key: string]: string | number | boolean | null; + }; + test: { + [key: string]: string | number | boolean | null; + }; + timeline: { + [key: string]: string | number | boolean | null; + }; +} + +export type { ActiveFormProps, OptionType, RowType }; diff --git a/src/utils/data.ts b/src/utils/data.ts new file mode 100644 index 0000000..557406c --- /dev/null +++ b/src/utils/data.ts @@ -0,0 +1,72 @@ +import { RowType } from "@/types/types"; + +export const data: RowType[] = [ + { + student: { + testTakers: "csdchsdcn", + program: "Himachal Students", + batch: "DL-12-Alpha-Eng-23", + grade: "9", + course: "NEET", + stream: "Medical", + }, + test: { + name: "cdsjcnjsnc", + id: "1", + sessionId: "cdsc", + sessionLink: "cdscdsc", + cmsId: "csdcs", + type: "assessment", + format: "major_test", + purpose: "baseline", + platform: "Quiz", + markingScheme: "4,-1", + optionalLimit: "na", + }, + timeline: { + startDate: "2023-08-11", + endDate: "2023-08-04", + startTime: "10:24", + endTime: "22:24", + reportSchedule: "dscsdc", + reportLink: "cdscjndsc", + isEnabled: false, + sessionType: "infinite", + synced: true, + }, + }, + { + student: { + testTakers: "csdchsdcn", + program: "Himachal Students", + batch: "DL-12-Alpha-Eng-23", + grade: "9", + course: "NEET", + stream: "Medical", + }, + test: { + name: "cdsjcnjsnc", + id: "1", + sessionId: "cdsc", + sessionLink: "cdscdsc", + cmsId: "csdcs", + type: "assessment", + format: "major_test", + purpose: "baseline", + platform: "Quiz", + markingScheme: "4,-1", + optionalLimit: "na", + }, + timeline: { + startDate: "2023-08-11", + endDate: "2023-08-04", + startTime: "10:24", + endTime: "22:24", + reportSchedule: "dscsdc", + reportLink: "cdscjndsc", + isEnabled: false, + sessionType: "infinite", + synced: true, + }, + }, +];