瀏覽代碼

created assignment form validation toast

develop
Ajay_S 3 年之前
父節點
當前提交
6df5a6df83
共有 10 個檔案被更改,包括 221 行新增80 行删除
  1. +64
    -65
      src/App.tsx
  2. +56
    -0
      src/components/Toast/Toast.module.scss
  3. +48
    -0
      src/components/Toast/Toast.tsx
  4. +14
    -1
      src/components/formInput/Input.tsx
  5. +0
    -1
      src/mockData/QuizDetails.tsx
  6. +1
    -1
      src/pages/assignment/Assignment.module.scss
  7. +2
    -2
      src/pages/assignment/SubmitAssignment.module.scss
  8. +30
    -9
      src/pages/assignment/SubmitAssignment.tsx
  9. +4
    -0
      src/pages/finalInterview/FinalInterview.tsx
  10. +2
    -1
      src/pages/technicalInterview/TechnicalInterview.tsx

+ 64
- 65
src/App.tsx 查看文件

@@ -1,5 +1,5 @@
import { Redirect, Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { IonApp, IonItem, IonRouterOutlet, setupIonicReact } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router'; import { IonReactRouter } from '@ionic/react-router';


/* Core CSS required for Ionic components to work properly */ /* Core CSS required for Ionic components to work properly */
@@ -38,8 +38,6 @@ import JoiningLetter from './pages/joiningLetter/JoiningLetter';
import Celebration from './pages/celebration/Celebration'; import Celebration from './pages/celebration/Celebration';
import SignaturePhoto from './pages/joiningLetter/SignaturePhoto'; import SignaturePhoto from './pages/joiningLetter/SignaturePhoto';
import TechinicalInterviewResults from './pages/technicalInterview/TechinicalInterviewResults'; import TechinicalInterviewResults from './pages/technicalInterview/TechinicalInterviewResults';
import CountdownTimer from './components/CountDownTimer/CountdownTimer';





setupIonicReact(); setupIonicReact();
@@ -48,67 +46,68 @@ const App: React.FC = () => (
<IonApp> <IonApp>
<IonReactRouter> <IonReactRouter>
<IonRouterOutlet> <IonRouterOutlet>
<Route exact path="/interviewRounds">
<InterviewRounds />
</Route>
<Route exact path="/skillInformationStep">
<SkillInformationStep />
</Route>
<Route exact path="/quiz">
<Quiz />
</Route>
<Route exact path="/preliminaryRound">
<PreliminaryRound />
</Route>
<Route exact path="/preliminaryRoundResults">
<PreliminaryRoundResults />
</Route>
<Route exact path="/technicalInterview">
<TechnicalInterview />
</Route>
<Route exact path="/technicalInterview/techinicalInterviewResults">
<TechinicalInterviewResults />
</Route>
<Route exact path="/assignment">
<Assignment />
</Route>
<Route exact path="/assignmentDetails">
<AssignmentDetails />
</Route>
<Route exact path="/SubmitAssignment">
<SubmitAssignment />
</Route>
<Route exact path="/ReviewAssignment">
<ReviewAssignment />
</Route>
<Route exact path="/assignmentCompleted">
<AssignmentCompleted />
</Route>
<Route exact path="/finalInterview">
<FinalInterview />
</Route>
<Route exact path="/finalInterview/results">
<FinalInterviewResult />
</Route>
<Route exact path="/closingDocs">
<ClosingDocs />
</Route>
<Route exact path="/verifiedDocs">
<VerifiedDocs />
</Route>
<Route exact path="/joiningLetter">
<JoiningLetter />
</Route>
<Route exact path="/joiningLetter/signaturePhoto">
<SignaturePhoto />
</Route>
<Route exact path="/celebration">
<Celebration />
</Route>
<Route exact path="/">
<Redirect to="/interviewRounds" />
</Route>

<Switch>
<Route exact path="/interviewRounds">
<InterviewRounds />
</Route>
<Route exact path="/skillInformationStep">
<SkillInformationStep />
</Route>
<Route exact path="/quiz">
<Quiz />
</Route>
<Route exact path="/preliminaryRound">
<PreliminaryRound />
</Route>
<Route exact path="/preliminaryRoundResults">
<PreliminaryRoundResults />
</Route>
<Route exact path="/technicalInterview">
<TechnicalInterview />
</Route>
<Route exact path="/technicalInterview/techinicalInterviewResults">
<TechinicalInterviewResults />
</Route>
<Route exact path="/assignment">
<Assignment />
</Route>
<Route exact path="/assignmentDetails">
<AssignmentDetails />
</Route>
<Route exact path="/SubmitAssignment">
<SubmitAssignment />
</Route>
<Route exact path="/ReviewAssignment">
<ReviewAssignment />
</Route>
<Route exact path="/assignmentCompleted">
<AssignmentCompleted />
</Route>
<Route exact path="/finalInterview">
<FinalInterview />
</Route>
<Route exact path="/finalInterview/results">
<FinalInterviewResult />
</Route>
<Route exact path="/closingDocs">
<ClosingDocs />
</Route>
<Route exact path="/verifiedDocs">
<VerifiedDocs />
</Route>
<Route exact path="/joiningLetter">
<JoiningLetter />
</Route>
<Route exact path="/joiningLetter/signaturePhoto">
<SignaturePhoto />
</Route>
<Route exact path="/celebration">
<Celebration />
</Route>
<Route exact path="/">
<Redirect to="/interviewRounds" />
</Route>
</Switch>
</IonRouterOutlet> </IonRouterOutlet>
</IonReactRouter> </IonReactRouter>
</IonApp> </IonApp>


+ 56
- 0
src/components/Toast/Toast.module.scss 查看文件

@@ -0,0 +1,56 @@
.toastContent {
width: 90%;
position: fixed;
bottom:5%;
left: 5%;
z-index: 10;

.toastHolder {
display: flex;
align-items: center;
justify-content: space-between;
border: 0.1rem solid transparent;
border-radius: 2.5rem;
background-color: white;
min-height: 4rem;
.messageHolder {
display: flex;
align-items: center;
margin-left: 1.5rem;

.text {
margin-left: 1rem;
font-size: 1.4rem;
}
}

.closeIcon {
color: #ec0b6d;
min-width: 20px;
height: 20px;
margin-right: 10px;
}

.checkIcon {
width: 20px;
height: 20px;
color: #00ae8d;
}
.errorIcon {
min-width: 20px;
height: 20px;
color: #ea7a7a;
}
}

.error {
box-shadow: 0 0 15px #ea7a7a;
}

.success {
box-shadow: 0 0 15px #00ae8d;
}

}

+ 48
- 0
src/components/Toast/Toast.tsx 查看文件

@@ -0,0 +1,48 @@
import { IonIcon, IonItem } from "@ionic/react";
import styles from "./Toast.module.scss";
import { checkmarkCircle, closeCircle, alertCircle } from 'ionicons/icons';
import { useEffect, useState } from "react";


interface OwnProps {
message: string;
messageType: string;
showToast: boolean;
}

const Toast: React.FC<OwnProps> = (props) => {

const [showToast, setShowToast] = useState(props.showToast);
console.log("show props", props.showToast);

useEffect(() => {
setShowToast(props.showToast);
}, [props.showToast]);

// const [showToast, setShowToast] = useState(props.showToast);
console.log(showToast)

const closeToast = () => {
setShowToast(false);
}

setTimeout(() => {
closeToast();
}, 3000);



return (
<div className={styles.toastContent}>
{showToast && < div className={styles.toastHolder + " " + styles.error} >
<div className={styles.messageHolder}>
<IonIcon className={styles.errorIcon} icon={alertCircle} />
<div className={styles.text}>invalid Input</div>
</div>
<IonIcon className={styles.closeIcon} icon={closeCircle} />
</div>}
</div >
);
}

export default Toast;

+ 14
- 1
src/components/formInput/Input.tsx 查看文件

@@ -1,14 +1,26 @@
import styles from './Input.module.scss'; import styles from './Input.module.scss';
import { IonIcon, IonInput, IonItem, IonLabel } from '@ionic/react'; import { IonIcon, IonInput, IonItem, IonLabel } from '@ionic/react';
import { useEffect, useState } from 'react';


interface Props { interface Props {
placeholder?: string; placeholder?: string;
type?: "text" | "email" | "password" | "number"; type?: "text" | "email" | "password" | "number";
icon?: string; icon?: string;
text?: string; text?: string;
isInputSet?: (isSet: boolean) => void;
} }


const Input: React.FC<Props> = (props) => { const Input: React.FC<Props> = (props) => {
const [inputText, setInputText] = useState<string | number | undefined>(undefined);

useEffect(() => {
if (inputText) {
props.isInputSet!(true);
} else {
props.isInputSet!(false);
}
}, [inputText])

return ( return (
<div className={styles.inputContainer}> <div className={styles.inputContainer}>
<div className={styles.inputHolderContainer}> <div className={styles.inputHolderContainer}>
@@ -21,7 +33,8 @@ const Input: React.FC<Props> = (props) => {
<IonLabel>{props.text}</IonLabel> <IonLabel>{props.text}</IonLabel>
} }
<IonInput type={props.type ? props.type : "text"} <IonInput type={props.type ? props.type : "text"}
placeholder={props.placeholder ? props.placeholder : ""}></IonInput>
placeholder={props.placeholder ? props.placeholder : ""}
onIonChange={e => setInputText(e.detail.value!)}></IonInput>
</IonItem> </IonItem>


</div> </div>


+ 0
- 1
src/mockData/QuizDetails.tsx 查看文件

@@ -6,7 +6,6 @@ interface QuizDetails {
timeLimit: number; timeLimit: number;
} }



let quizDetails: QuizDetails[] = [ let quizDetails: QuizDetails[] = [
{ {
question: "How would you correctly display, “Hello, how are you?”?", question: "How would you correctly display, “Hello, how are you?”?",


+ 1
- 1
src/pages/assignment/Assignment.module.scss 查看文件

@@ -1,7 +1,7 @@
.assignment { .assignment {


.description { .description {
height: 75vh;
height: 74vh;


.icon { .icon {
margin-top: 4rem; margin-top: 4rem;


+ 2
- 2
src/pages/assignment/SubmitAssignment.module.scss 查看文件

@@ -2,7 +2,7 @@
.description { .description {
height: 50vh; height: 50vh;
.icon { .icon {
margin-top: 4rem;
padding-top: 4rem;
display: flex; display: flex;
justify-content: center; justify-content: center;
ion-icon { ion-icon {
@@ -34,13 +34,13 @@
.inputHolder { .inputHolder {
width: 95%; width: 95%;
margin: 0 auto; margin: 0 auto;
height: 25vh;
} }
.submitAssigment { .submitAssigment {
text-decoration: none; text-decoration: none;
ion-button { ion-button {
width: 90%; width: 90%;
margin: 0 auto; margin: 0 auto;
margin-top: 12rem;
--background: var(--primary-button-color); --background: var(--primary-button-color);
} }
} }

+ 30
- 9
src/pages/assignment/SubmitAssignment.tsx 查看文件

@@ -1,15 +1,32 @@
import styles from "./SubmitAssignment.module.scss"; import styles from "./SubmitAssignment.module.scss";
import { IonButton, IonContent, IonIcon, IonPage } from "@ionic/react"
import { IonButton, IonContent, IonIcon, IonPage, useIonToast } from "@ionic/react"
import assignmentImage from "../../assets/icons/Assignment.svg"; import assignmentImage from "../../assets/icons/Assignment.svg";
import StepHeader from "../../components/stepsHeader/StepHeader"; import StepHeader from "../../components/stepsHeader/StepHeader";
import Input from "../../components/formInput/Input"; import Input from "../../components/formInput/Input";
import linkIcon from "../../assets/icons/link.svg";
import time from "../../assets/icons/time.svg";
import { linkOutline } from 'ionicons/icons'
import { linkOutline } from 'ionicons/icons';
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useState } from "react";


const SubmitAssignment: React.FC = () => { const SubmitAssignment: React.FC = () => {

const [isInput, setIsInput] = useState(false);
const [present, dismiss] = useIonToast();

const isInputSet = (isSet: boolean) => {
setIsInput(isSet);
}


const showToast = () => {
if (!isInput) {
present({
buttons: [{ text: 'close', handler: () => dismiss() }],
message: 'insert project link to submit',
duration: 2000
})
}
}

return ( return (
<IonPage> <IonPage>
<StepHeader roundName="Assignment" stepNumber={4} /> <StepHeader roundName="Assignment" stepNumber={4} />
@@ -19,7 +36,6 @@ const SubmitAssignment: React.FC = () => {
<div className={styles.description}> <div className={styles.description}>
<div className={styles.icon}> <div className={styles.icon}>
<IonIcon src={assignmentImage} /> <IonIcon src={assignmentImage} />

</div> </div>


<div className={styles.stepDescription}> <div className={styles.stepDescription}>
@@ -31,12 +47,17 @@ const SubmitAssignment: React.FC = () => {
</div> </div>


<div className={styles.inputHolder}> <div className={styles.inputHolder}>
<Input placeholder="Insert the project Link" icon={linkOutline} />
<Input
placeholder="Insert the project Link"
icon={linkOutline}
isInputSet={isInputSet} />
</div> </div>
<Link to="/ReviewAssignment"
className={styles.submitAssigment}>
<Link to={isInput ? "/ReviewAssignment" : "/SubmitAssignment"}
className={styles.submitAssigment}
onClick={showToast}>
<IonButton shape="round" expand='block'>Submit</IonButton> <IonButton shape="round" expand='block'>Submit</IonButton>
</Link> </Link>

</IonContent> </IonContent>
</IonPage> </IonPage>
); );


+ 4
- 0
src/pages/finalInterview/FinalInterview.tsx 查看文件

@@ -7,6 +7,8 @@ import locationIcon from "../../assets/icons/location.svg";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useState } from "react"; import { useState } from "react";
import TimeSlot from "../../components/timeSlot/TimeSlot"; import TimeSlot from "../../components/timeSlot/TimeSlot";
import { useCountdown } from "../../components/CountDownTimer/useCountdown";
import { addDays } from "date-fns";


interface dates { interface dates {
date: string; date: string;
@@ -18,6 +20,8 @@ const FinalInterview: React.FC = () => {
const [isDateSet, setDate] = useState<boolean>(false); const [isDateSet, setDate] = useState<boolean>(false);
const [isTimeSlot, setTimeSlot] = useState<boolean>(false); const [isTimeSlot, setTimeSlot] = useState<boolean>(false);


const [days, hours, minutes, seconds] = useCountdown(addDays(new Date(), 3));

const timeSlots = ["11:00 AM - 1:00 pm", "1:00 PM - 3:00 pm", "3:00 PM - 5:00 pm"]; const timeSlots = ["11:00 AM - 1:00 pm", "1:00 PM - 3:00 pm", "3:00 PM - 5:00 pm"];


const dates: dates[] = [ const dates: dates[] = [


+ 2
- 1
src/pages/technicalInterview/TechnicalInterview.tsx 查看文件

@@ -21,7 +21,8 @@ const TechnicalInterview: React.FC = () => {
const [isDateSet, setDate] = useState<boolean>(false); const [isDateSet, setDate] = useState<boolean>(false);
const [isTimeSlot, setTimeSlot] = useState<boolean>(false); const [isTimeSlot, setTimeSlot] = useState<boolean>(false);


const [days, hours, minutes, seconds] = useCountdown(addDays(new Date(), 2));

const [days, hours, minutes, seconds] = useCountdown(addDays(new Date(), 3));


console.log(days, hours, minutes, seconds); console.log(days, hours, minutes, seconds);




Loading…
取消
儲存