Skip to content

Commit 47b693a

Browse files
JXP25yasharyasaxenaPrincekumarofficial
authored
Develop (#261)
* Added appropiate message for larger file upload fail and accepted file types (#257) * fix: Added Max size for pdf and allowed file size * Update JobDetails.tsx --------- Co-authored-by: Jai Pannu <142983705+JaiPannu-IITI@users.noreply.github.com> * Added % in label and checks for marks and cpi (#258) * fix: Added Max size for pdf and allowed file size * Update JobDetails.tsx * fix: added checks and errors for marks and cpi * Update JobDetails.tsx --------- Co-authored-by: Jai Pannu <142983705+JaiPannu-IITI@users.noreply.github.com> * add recaptcha (#260) --------- Co-authored-by: Yash Arya Saxena <105877652+yasharyasaxena@users.noreply.github.com> Co-authored-by: Prince Kumar <x.prince.x@outlook.com>
1 parent fc3d0e4 commit 47b693a

7 files changed

Lines changed: 167 additions & 25 deletions

File tree

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ GOOGLE_CLIENT_ID=
44
GOOGLE_CLIENT_SECRET=
55
NEXT_PUBLIC_SECRET=secret
66
NEXT_PUBLIC_BASE_PATH="/portal"
7-
NEXTAUTH_URL=https://localhost:3000/portal/api/auth
7+
NEXTAUTH_URL=https://localhost:3000/portal/api/auth
8+
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"react-cool-onclickoutside": "^1.7.0",
6868
"react-dom": "latest",
6969
"react-google-button": "^0.7.2",
70+
"react-google-recaptcha": "^3.1.0",
7071
"react-hot-toast": "^2.4.1",
7172
"react-icons": "^4.12.0",
7273
"react-modal": "^3.16.1",

src/app/(authroutes)/passwordless/[token]/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const LoginPage = ({
2929
router.push("/recruiter");
3030
} catch (error) {
3131
toast.error("Some Error Occurred");
32+
console.error("Error during passwordless login:", error);
3233
} finally {
3334
setLoading(false);
3435
}

src/components/JAF/JobDetails.tsx

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,29 @@ const JobDetails = ({
340340
}
341341
help={toErrorString(errors.attachments)}
342342
>
343-
<Upload fileList={fileList} onChange={handleFileChange}>
343+
<Upload
344+
fileList={fileList}
345+
onChange={handleFileChange}
346+
beforeUpload={(file) => {
347+
const isPdf = file.type === "application/pdf";
348+
if (!isPdf) {
349+
message.error("You can only upload PDF files!");
350+
return Upload.LIST_IGNORE;
351+
}
352+
const isLt2M = file.size / 1024 / 1024 <= 2;
353+
if (!isLt2M) {
354+
message.error("File must be smaller than 2MB!");
355+
return Upload.LIST_IGNORE;
356+
}
357+
return true;
358+
}}
359+
>
344360
<Button icon={<UploadOutlined />}>Click to Upload</Button>
345361
</Upload>
362+
<ul className="list-disc text-black opacity-70 text-xs pl-5">
363+
<li>Accepted file types .pdf</li>
364+
<li>File size &lt; 2 MB.</li>
365+
</ul>
346366
</Form.Item>
347367
</Col>
348368
</Row>
@@ -444,8 +464,6 @@ const JobDetails = ({
444464
<Button type="dashed" onClick={() => add()} block>
445465
+ Add Test
446466
</Button>
447-
448-
449467
</>
450468
)}
451469
</Form.List>
@@ -490,8 +508,6 @@ const JobDetails = ({
490508
<Button type="dashed" onClick={() => add()} block>
491509
+ Add Interview
492510
</Button>
493-
494-
495511
</>
496512
)}
497513
</Form.List>
@@ -632,24 +648,102 @@ const JobDetails = ({
632648
<Row gutter={24}>
633649
<Col span={12}>
634650
<Form.Item
635-
label="Tenth Marks"
651+
label="Tenth Marks (%)"
636652
name={[field.name, "tenthMarks"]}
653+
rules={[
654+
{
655+
validator: (_, value) => {
656+
if (value === undefined || value === "")
657+
return Promise.resolve();
658+
const strValue = String(value).replace(/\s+/g, "");
659+
if (!/^\d*\.?\d*$/.test(strValue)) {
660+
return Promise.reject(
661+
"Please enter a positive decimal value",
662+
);
663+
}
664+
const num = parseFloat(strValue);
665+
if (isNaN(num) || num > 100) {
666+
return Promise.reject(
667+
"Value must be less than or equal to 100",
668+
);
669+
}
670+
return Promise.resolve();
671+
},
672+
},
673+
]}
674+
getValueFromEvent={(e) => {
675+
const value = e.target.value.replace(/\s+/g, "");
676+
return value;
677+
}}
637678
>
638679
<Input placeholder="Tenth Marks" />
639680
</Form.Item>
640681
</Col>
641682
<Col span={12}>
642683
<Form.Item
643-
label="Twelveth Marks"
644-
name={[field.name, "twelvethMarks"]}
684+
label="Twelfth Marks (%)"
685+
name={[field.name, "twelthMarks"]}
686+
rules={[
687+
{
688+
validator: (_, value) => {
689+
if (value === undefined || value === "")
690+
return Promise.resolve();
691+
const strValue = String(value).replace(/\s+/g, "");
692+
if (!/^\d*\.?\d*$/.test(strValue)) {
693+
return Promise.reject(
694+
"Please enter a positive decimal value",
695+
);
696+
}
697+
const num = parseFloat(strValue);
698+
if (isNaN(num) || num > 100) {
699+
return Promise.reject(
700+
"Value must be less than or equal to 100",
701+
);
702+
}
703+
return Promise.resolve();
704+
},
705+
},
706+
]}
707+
getValueFromEvent={(e) => {
708+
const value = e.target.value.replace(/\s+/g, "");
709+
return value;
710+
}}
645711
>
646-
<Input placeholder="Twelveth Marks" />
712+
<Input placeholder="Twelfth Marks" />
647713
</Form.Item>
648714
</Col>
649715
</Row>
650716
<Row gutter={24}>
651717
<Col span={12}>
652-
<Form.Item label="Min CPI" name={[field.name, "minCPI"]}>
718+
<Form.Item
719+
label="Min CPI"
720+
name={[field.name, "minCPI"]}
721+
rules={[
722+
{
723+
pattern: /^\d*\.?\d*$/,
724+
message: "Please enter a positive decimal value",
725+
},
726+
{
727+
validator: (_, value) => {
728+
if (value === undefined || value === "")
729+
return Promise.resolve();
730+
if (!/^\d*\.?\d*$/.test(value))
731+
return Promise.resolve();
732+
const num = parseFloat(value);
733+
if (isNaN(num) || num > 10) {
734+
return Promise.reject(
735+
"Value must be less than or equal to 10",
736+
);
737+
}
738+
return Promise.resolve();
739+
},
740+
},
741+
]}
742+
getValueFromEvent={(e) => {
743+
const value = e.target.value.replace(/\s+/g, "");
744+
return value;
745+
}}
746+
>
653747
<Input placeholder="Min CPI" />
654748
</Form.Item>
655749
</Col>

src/components/loginForms/recruiterSignup.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import { MultiSelect } from "../ui/multiselect";
3232
import Link from "next/link";
3333
import dynamic from "next/dynamic";
3434
import { useRouter } from "next/navigation";
35+
import ReCAPTCHA from "react-google-recaptcha";
36+
import { validateCaptcha } from "@/helpers/api";
3537

3638
const Collapsible = dynamic(() => import("@/components/ui/collapsible"), {
3739
ssr: false,
@@ -252,6 +254,7 @@ export const RecruiterForm = ({
252254
export default function RecruiterSignup() {
253255
const [companies, setCompanies] = useState([]);
254256
const [createCompany, setCreateCompany] = useState(false);
257+
const [captchaToken, setCaptchaToken] = useState("");
255258
const router = useRouter();
256259

257260
const [companyFormData, setCompanyFormData] = useState<CompanyPostFC>({
@@ -302,6 +305,19 @@ export default function RecruiterSignup() {
302305
};
303306

304307
const handleSubmit = async () => {
308+
if (!captchaToken) return toast.error("Please complete the captcha");
309+
310+
try {
311+
const captchaRes = await validateCaptcha(captchaToken);
312+
console.log("Captcha response:", captchaRes);
313+
314+
if (!captchaRes) {
315+
return toast.error("Captcha verification failed");
316+
}
317+
} catch (error) {
318+
return toast.error("Captcha verification failed");
319+
}
320+
305321
if (createCompany) {
306322
try {
307323
const data = await postCompany(companyFormData);
@@ -455,6 +471,11 @@ export default function RecruiterSignup() {
455471
</Collapsible>
456472
)}
457473
</form>
474+
<hr className="my-4" />
475+
<ReCAPTCHA
476+
sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY || ""}
477+
onChange={(token) => setCaptchaToken(token)}
478+
/>
458479
</CardContent>
459480
<CardFooter>
460481
<div className="flex justify-end space-x-1">

src/helpers/api.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -550,26 +550,25 @@ export const createJobEvent = async (
550550
};
551551

552552
export const updateEvent = async (
553-
body:
554-
[
555-
{
556-
id: string;
557-
jobId: string;
558-
roundNumber: number;
559-
type: string;
560-
metadata: string;
561-
startDateTime: string;
562-
endDateTime: string;
563-
visibleToRecruiter: boolean;
564-
}]
553+
body: [
554+
{
555+
id: string;
556+
jobId: string;
557+
roundNumber: number;
558+
type: string;
559+
metadata: string;
560+
startDateTime: string;
561+
endDateTime: string;
562+
visibleToRecruiter: boolean;
563+
},
564+
],
565565
) => {
566566
return apiCall(`/events`, {
567567
method: "PATCH",
568568
body: body,
569569
});
570570
};
571571

572-
573572
export const login = async (email: string, role: string) => {
574573
const response = await apiCall("/auth/login/", {
575574
method: "POST",
@@ -697,3 +696,12 @@ export const fetchcompanies = async () => {
697696
export const fetchClashes = async (jobId: string) => {
698697
return apiCall(`/clashes/${jobId}`);
699698
};
699+
700+
export const validateCaptcha = async (captcha: string) => {
701+
const res = await apiCall("/auth/verify-captcha", {
702+
method: "POST",
703+
body: { token: captcha },
704+
isAuth: false,
705+
});
706+
return res;
707+
};

yarn.lock

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5837,7 +5837,7 @@ progress@^2.0.3:
58375837
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
58385838
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
58395839

5840-
prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
5840+
prop-types@^15.5.0, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
58415841
version "15.8.1"
58425842
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
58435843
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -6282,6 +6282,14 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
62826282
rc-resize-observer "^1.0.0"
62836283
rc-util "^5.36.0"
62846284

6285+
react-async-script@^1.2.0:
6286+
version "1.2.0"
6287+
resolved "https://registry.yarnpkg.com/react-async-script/-/react-async-script-1.2.0.tgz#ab9412a26f0b83f5e2e00de1d2befc9400834b21"
6288+
integrity sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==
6289+
dependencies:
6290+
hoist-non-react-statics "^3.3.0"
6291+
prop-types "^15.5.0"
6292+
62856293
react-chartjs-2@^5.2.0:
62866294
version "5.2.0"
62876295
resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz#43c1e3549071c00a1a083ecbd26c1ad34d385f5d"
@@ -6320,6 +6328,14 @@ react-google-button@^0.7.2:
63206328
dependencies:
63216329
prop-types "^15.7.2"
63226330

6331+
react-google-recaptcha@^3.1.0:
6332+
version "3.1.0"
6333+
resolved "https://registry.yarnpkg.com/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz#44aaab834495d922b9d93d7d7a7fb2326315b4ab"
6334+
integrity sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==
6335+
dependencies:
6336+
prop-types "^15.5.0"
6337+
react-async-script "^1.2.0"
6338+
63236339
react-hot-toast@^2.4.1:
63246340
version "2.4.1"
63256341
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"

0 commit comments

Comments
 (0)