Skip to content

Commit 843b06c

Browse files
added resume ai
1 parent 0917021 commit 843b06c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3582
-63
lines changed

app/dashboard/layout.tsx

+11-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import {
33
BarChart,
44
Bot,
5+
File,
56
Home,
67
LinkedinIcon,
78
Mail,
@@ -56,11 +57,21 @@ export default function DashLayout({
5657
icon: <TableProperties size={16} />,
5758
link: "/dashboard/forms",
5859
},
60+
{
61+
name: "resume",
62+
icon: <File size={16} />,
63+
link: "/dashboard/resume",
64+
},
5965
{
6066
name: "content",
6167
icon: <BarChart size={16} />,
6268
link: "/dashboard/content",
6369
},
70+
{
71+
name: "emailer",
72+
icon: <Mail size={16} />,
73+
link: "/dashboard/emailer",
74+
},
6475
{
6576
name: "toplinkedin",
6677
icon: <LinkedinIcon size={16} />,
@@ -71,11 +82,6 @@ export default function DashLayout({
7182
icon: <Newspaper size={16} />,
7283
link: "/dashboard/headlines",
7384
},
74-
{
75-
name: "emailer",
76-
icon: <Mail size={16} />,
77-
link: "/dashboard/emailer",
78-
},
7985
{
8086
name: "chatbot",
8187
icon: <Bot size={16} />,

app/dashboard/page.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import {
1111
ArrowRight,
1212
BotMessageSquare,
13+
FileHeart,
1314
Loader2,
1415
MailPlus,
1516
Speech,
@@ -73,6 +74,25 @@ export default function Dashboard({}: Props) {
7374
</Button>
7475
</CardContent>
7576
</Card>
77+
<Card className="hover:-translate-y-1 shadow hover:shadow-blue-500/40 hover:shadow-md duration-500 transition-all border border-violet-500">
78+
<CardHeader className="flex gap-4">
79+
<FileHeart size={50} />
80+
<div>
81+
<CardTitle>AI Resume ✨</CardTitle>
82+
<CardDescription>
83+
Create your resume with our easy-to-use AI resume builder.
84+
</CardDescription>
85+
</div>
86+
</CardHeader>
87+
<CardContent>
88+
<Button asChild size={"sm"}>
89+
<Link href="/dashboard/resume">
90+
Create
91+
<ArrowRight size={18} />
92+
</Link>
93+
</Button>
94+
</CardContent>
95+
</Card>
7696
<Card className="hover:-translate-y-1 shadow hover:shadow-blue-500/40 hover:shadow-md duration-500 transition-all border border-blue-500">
7797
<CardHeader className="flex gap-4">
7898
<BotMessageSquare size={50} />
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React, { use } from "react";
2+
import { currentUser } from "@clerk/nextjs/server";
3+
import { checkResumeOwnership } from "@/lib/actions/resume.actions";
4+
import { redirect } from "next/navigation";
5+
import ResumeEditor from "@/components/layout/my-resume/ResumeEditor";
6+
7+
const EditResume = async ({ params }: { params: { id: string } }) => {
8+
const user = await currentUser();
9+
const isResumeOwner = await checkResumeOwnership(user?.id || "", params.id);
10+
11+
if (!isResumeOwner) {
12+
return redirect("/dashboard");
13+
}
14+
15+
return (
16+
<>
17+
<ResumeEditor params={params} userId={user?.id} />
18+
</>
19+
);
20+
};
21+
22+
export default EditResume;

app/dashboard/resume/page.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import DashboardCards from "@/components/layout/DashboardCards";
2+
3+
export default function Resume() {
4+
return (
5+
<>
6+
<div className="w-full flex flex-col gap-8 md:p-5">
7+
<div className="bg-gradient-to-tl from-green-300 via-blue-500 to-purple-600 p-10 rounded-lg mb-10">
8+
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-start gap-x-10 gap-y-4">
9+
<div>
10+
<h2 className="font-bold text-3xl text-white mb-2">
11+
create your resume.
12+
</h2>
13+
<h2 className="text-gray-200">
14+
Create your resume with our easy-to-use AI resume builder. Also
15+
download your resume in PDF format.
16+
</h2>
17+
</div>
18+
</div>
19+
</div>
20+
21+
<DashboardCards />
22+
</div>
23+
</>
24+
);
25+
}

app/resume/[id]/page.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import FinalResumeView from "@/components/layout/ResumeView";
2+
import React from "react";
3+
import {
4+
checkResumeOwnership,
5+
fetchResume,
6+
} from "@/lib/actions/resume.actions";
7+
import { currentUser } from "@clerk/nextjs/server";
8+
9+
const MyResume = async ({ params }: { params: { id: string } }) => {
10+
const user = await currentUser();
11+
const isResumeOwner = await checkResumeOwnership(user?.id || "", params.id);
12+
13+
return <FinalResumeView params={params} isOwnerView={isResumeOwner} />;
14+
};
15+
16+
export default MyResume;

bun.lockb

18.7 KB
Binary file not shown.

components/common/AddResume.tsx

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
"use client";
2+
3+
import { Loader2, PlusSquare } from "lucide-react";
4+
import {
5+
Dialog,
6+
DialogContent,
7+
DialogDescription,
8+
DialogHeader,
9+
DialogTitle,
10+
} from "../ui/dialog"
11+
import { v4 as uuidv4 } from "uuid";
12+
import React, { useState } from "react";
13+
import { z } from "zod";
14+
import { Button } from "../ui/button";
15+
import { Input } from "../ui/input";
16+
import { useForm } from "react-hook-form";
17+
import { ResumeNameValidationSchema } from "@/lib/validations/resume";
18+
import { zodResolver } from "@hookform/resolvers/zod";
19+
import {
20+
Form,
21+
FormControl,
22+
FormField,
23+
FormItem,
24+
FormLabel,
25+
FormMessage,
26+
} from "../ui/form";
27+
import { createResume } from "@/lib/actions/resume.actions";
28+
import { toast } from "../ui/use-toast";
29+
import { useRouter } from "next-nprogress-bar";
30+
31+
const AddResume = ({ userId }: { userId: string | undefined }) => {
32+
const router = useRouter();
33+
const [openDialog, setOpenDialog] = useState(false);
34+
const [isLoading, setIsLoading] = useState(false);
35+
36+
const form = useForm({
37+
resolver: zodResolver(ResumeNameValidationSchema),
38+
defaultValues: {
39+
name: "",
40+
},
41+
});
42+
43+
const onSubmit = async (
44+
values: z.infer<typeof ResumeNameValidationSchema>
45+
) => {
46+
if (userId === undefined) {
47+
return;
48+
}
49+
50+
setIsLoading(true);
51+
52+
const uuid = uuidv4();
53+
54+
const result = await createResume({
55+
resumeId: uuid,
56+
userId: userId,
57+
title: values.name,
58+
});
59+
60+
if (result.success) {
61+
form.reset();
62+
63+
const resume = JSON.parse(result.data!);
64+
65+
router.push(`/dashboard/resume/${resume.resumeId}/edit`);
66+
} else {
67+
setIsLoading(false);
68+
69+
toast({
70+
title: "Uh Oh! Something went wrong.",
71+
description: result?.error,
72+
variant: "destructive",
73+
className: "bg-white",
74+
});
75+
}
76+
};
77+
78+
return (
79+
<>
80+
<div
81+
className="relative aspect-[1/1.2] border border-dashed border-slate-300 flex items-center justify-center bg-slate-100 rounded-xl hover:scale-105 hover:shadow-md transition-all cursor-pointer"
82+
onClick={() => userId && setOpenDialog(true)}
83+
>
84+
<PlusSquare className="text-slate-500" />
85+
</div>
86+
87+
<Dialog open={openDialog} onOpenChange={setOpenDialog}>
88+
<DialogContent>
89+
<DialogHeader>
90+
<DialogTitle>Create New Resume</DialogTitle>
91+
<DialogDescription>
92+
Enter the title of your resume here. Click create when you're
93+
done.
94+
</DialogDescription>
95+
</DialogHeader>
96+
<Form {...form}>
97+
<form
98+
onSubmit={form.handleSubmit(onSubmit)}
99+
className="comment-form"
100+
>
101+
<FormField
102+
control={form.control}
103+
name="name"
104+
render={({ field }) => (
105+
<FormItem>
106+
<FormLabel>
107+
<p className="mt-2 mb-3 text-slate-700 font-semibold">
108+
Resume Title:
109+
</p>
110+
</FormLabel>
111+
<FormControl>
112+
<Input
113+
type="text"
114+
placeholder="Example: Android Developer Resume"
115+
className="no-focus"
116+
autoComplete="off"
117+
{...field}
118+
/>
119+
</FormControl>
120+
<FormMessage />
121+
</FormItem>
122+
)}
123+
/>
124+
<div className="mt-10 flex justify-end gap-5">
125+
<button
126+
type="button"
127+
onClick={() => setOpenDialog(false)}
128+
className="btn-ghost"
129+
disabled={isLoading}
130+
>
131+
Cancel
132+
</button>
133+
<Button type="submit" disabled={isLoading}>
134+
{isLoading ? (
135+
<>
136+
<Loader2 size={20} className="animate-spin" /> &nbsp;
137+
Creating
138+
</>
139+
) : (
140+
"Create"
141+
)}
142+
</Button>
143+
</div>
144+
</form>
145+
</Form>
146+
</DialogContent>
147+
</Dialog>
148+
</>
149+
);
150+
};
151+
152+
export default AddResume;

0 commit comments

Comments
 (0)