Skip to content

Commit 139175f

Browse files
authored
Feat/admin UI (#553)
* fix: deleted jobs were showing * feat: jobs management page done * feat: added new ui for the payment and recruiters * fix: minor changes * fix:fixed responsiveness * fix:minor fix * feat:removed payment * fix:removed payments * feat:added filters * feat:added recruiters * fix:minor change * fix:minor changes * fix:filter fixed * fix: fixed responsiveness * fix:minor change
1 parent 5e66c62 commit 139175f

19 files changed

+561
-130
lines changed

prisma/schema.prisma

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,23 @@ model User {
2525
project Project[]
2626
resume String?
2727
28-
oauthProvider OauthProvider? // Tracks OAuth provider (e.g., 'google')
29-
oauthId String?
30-
28+
oauthProvider OauthProvider? // Tracks OAuth provider (e.g., 'google')
29+
oauthId String?
30+
createdAt DateTime @default(now())
3131
blockedByAdmin DateTime?
32-
onBoard Boolean @default(false)
32+
onBoard Boolean @default(false)
3333
bookmark Bookmark[]
34+
companyId String? @unique
35+
company Company? @relation(fields: [companyId], references: [id])
36+
}
37+
38+
model Company {
39+
id String @id @default(cuid())
40+
companyName String
41+
companyLogo String?
42+
companyEmail String
43+
companyBio String
44+
user User?
3445
}
3546

3647
enum OauthProvider {

prisma/seed.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,21 @@ const prisma = new PrismaClient();
1414
const users = [
1515
{ id: '1', name: 'Jack', email: '[email protected]' },
1616
{ id: '2', name: 'Admin', email: '[email protected]', role: Role.ADMIN, onBoard: true },
17-
{ id: '3', name: 'Hr', email: '[email protected]', role: Role.HR },
17+
{ id: '3', companyId: '1', name: 'Hr', email: '[email protected]', role: Role.HR, onBoard: true },
18+
{ id: '4', companyId: '2', name: 'John', email: '[email protected]', role: Role.HR, onBoard: true },
19+
{ id: '5', companyId: '3', name: 'Jane', email: '[email protected]', role: Role.HR, onBoard: true },
20+
21+
1822
];
1923

24+
25+
const companies = [
26+
{ id: '1', compnayEmail: "[email protected]", companyName: 'Tech Corp', companyBio: 'Leading tech solutions provider specializing in innovative web development.', companyLogo: '/main.svg' },
27+
{ id: '2', companyEmail: "[email protected]", companyName: 'Global Solutions', companyBio: 'Global Solutions offers comprehensive IT services for businesses worldwide.', companyLogo: '/main.svg' },
28+
{ id: '3', companyEmail: '[email protected]', companyName: 'Innovatech', companyBio: 'Innovatech specializes in backend systems and cloud-based solutions.', companyLogo: '/main.svg' },
29+
]
30+
31+
2032
let jobs = [
2133
{
2234
id: '1',
@@ -328,6 +340,7 @@ async function seedUsers() {
328340
password: hashedPassword,
329341
role: u.role || Role.USER,
330342
emailVerified: new Date(),
343+
companyId: u.companyId
331344
},
332345
});
333346
console.log(`User created or updated: ${u.email}`);
@@ -340,6 +353,28 @@ async function seedUsers() {
340353
console.error('Error seeding users:', error);
341354
}
342355
}
356+
async function seedCompanies() {
357+
try {
358+
await Promise.all(
359+
companies.map(async (c) =>
360+
prisma.company.upsert({
361+
where: { id: c.id },
362+
create: {
363+
id: c.id,
364+
companyName: c.companyName,
365+
companyEmail: c.companyEmail ?? "[email protected]",
366+
companyBio: c.companyBio,
367+
companyLogo: c.companyLogo,
368+
},
369+
update: {},
370+
})
371+
)
372+
);
373+
console.log('✅ Company seed completed successfully');
374+
} catch (error) {
375+
console.error('Error seeding companies:', error);
376+
}
377+
}
343378

344379
async function seedJobs() {
345380
try {
@@ -401,6 +436,7 @@ async function seedJobs() {
401436
}
402437

403438
async function main() {
439+
await seedCompanies();
404440
await seedUsers();
405441
await seedJobs();
406442
}

src/actions/job.action.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export const getAllJobs = withSession<
156156
skills: true,
157157
address: true,
158158
workMode: true,
159+
expired: true,
159160
category: true,
160161
minSalary: true,
161162
maxSalary: true,
@@ -219,6 +220,7 @@ export const getRecommendedJobs = withServerActionAsyncCatcher<
219220
maxSalary: true,
220221
postedAt: true,
221222
skills: true,
223+
expired: true,
222224
isVerifiedJob: true,
223225
companyLogo: true,
224226
},
@@ -252,6 +254,7 @@ export const getRecommendedJobs = withServerActionAsyncCatcher<
252254
companyLogo: true,
253255
minExperience: true,
254256
maxExperience: true,
257+
expired: true,
255258
isVerifiedJob: true,
256259
category: true,
257260
},
@@ -294,6 +297,7 @@ export const getJobById = withServerActionAsyncCatcher<
294297
minExperience: true,
295298
maxExperience: true,
296299
skills: true,
300+
expired: true,
297301
address: true,
298302
workMode: true,
299303
hasSalaryRange: true,
@@ -352,6 +356,7 @@ export const getRecentJobs = async () => {
352356
minExperience: true,
353357
maxExperience: true,
354358
skills: true,
359+
expired: true,
355360
postedAt: true,
356361
companyLogo: true,
357362
type: true,
@@ -601,6 +606,7 @@ export async function GetBookmarkByUserId() {
601606
minSalary: true,
602607
maxSalary: true,
603608
postedAt: true,
609+
expired: true,
604610
companyLogo: true,
605611
},
606612
},

src/actions/user.profile.actions.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,39 @@ export const getUserDetails = async () => {
317317
return new ErrorHandler('Internal server error', 'DATABASE_ERROR');
318318
}
319319
};
320+
321+
export const getUserRecruiters = async () => {
322+
const auth = await getServerSession(authOptions);
323+
324+
if (!auth || !auth?.user?.id || auth?.user?.role !== 'ADMIN')
325+
throw new ErrorHandler('Not Authorized', 'UNAUTHORIZED');
326+
try {
327+
const res = await prisma.user.findMany({
328+
where: {
329+
role: 'HR',
330+
},
331+
select: {
332+
id: true,
333+
email: true,
334+
name: true,
335+
createdAt: true,
336+
_count: {
337+
select: {
338+
jobs: true,
339+
},
340+
},
341+
company: {
342+
select: {
343+
companyName: true,
344+
companyEmail: true,
345+
},
346+
},
347+
},
348+
});
349+
return new SuccessResponse('Recruiter SuccessFully Fetched', 200, {
350+
recruiters: res,
351+
}).serialize();
352+
} catch (_error) {
353+
return new ErrorHandler('Internal server error', 'DATABASE_ERROR');
354+
}
355+
};

src/app/manage/page.tsx renamed to src/app/manage/jobs/page.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ const ManageJob = async ({
2525
redirect('/jobs');
2626
}
2727
const searchParamss = parsedData.data;
28-
return (
29-
<div className="container">
30-
<JobManagement searchParams={searchParamss} />
31-
</div>
32-
);
28+
return <JobManagement searchParams={searchParamss} />;
3329
};
3430

3531
export default ManageJob;

src/app/manage/recruiters/page.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { getUserRecruiters } from '@/actions/user.profile.actions';
2+
import ManageRecruiters from '@/components/ManageRecruiters';
3+
4+
import { options } from '@/lib/auth';
5+
import { getServerSession } from 'next-auth';
6+
import { redirect } from 'next/navigation';
7+
import React from 'react';
8+
9+
const RecruitersPage = async () => {
10+
const server = await getServerSession(options);
11+
if (!server?.user) {
12+
redirect('/api/auth/signin');
13+
} else if (server.user.role !== 'ADMIN') {
14+
redirect('/jobs');
15+
}
16+
17+
const Recruiters = await getUserRecruiters();
18+
19+
return <ManageRecruiters recruiters={Recruiters} />;
20+
};
21+
22+
export default RecruitersPage;

src/components/DeleteDialog.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button } from './ui/button';
44
import { useToast } from './ui/use-toast';
55
import { toggleDeleteJobById } from '@/actions/job.action';
66
import { JobType } from '@/types/jobs.types';
7+
import icons from '@/lib/icons';
78
import {
89
Dialog,
910
DialogTrigger,
@@ -13,7 +14,6 @@ import {
1314
DialogDescription,
1415
DialogFooter,
1516
} from './ui/dialog';
16-
import { ArchiveRestore, Trash } from 'lucide-react';
1717

1818
const JobDialog = ({ job }: { job: JobType }) => {
1919
const [dialogOpen, setDialogOpen] = useState(false); // State to manage dialog visibility
@@ -42,15 +42,19 @@ const JobDialog = ({ job }: { job: JobType }) => {
4242
role="button"
4343
onClick={() => setDialogOpen(true)}
4444
>
45-
<ArchiveRestore /> {/* Icon for restoring the job */}
45+
<Button variant="ghost" size="icon">
46+
<icons.ArchiveRestore className="h-7 w-5 text-green-500" />
47+
</Button>
4648
</span>
4749
) : (
4850
<span
4951
className="mr-5"
5052
role="button"
5153
onClick={() => setDialogOpen(true)}
5254
>
53-
<Trash /> {/* Icon for deleting the job */}
55+
<Button variant="ghost" size="icon">
56+
<icons.trash className="h-7 w-5 text-red-500" />
57+
</Button>
5458
</span>
5559
)}
5660
</DialogTrigger>

src/components/JobManagement.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react';
22
import { getAllJobs } from '@/actions/job.action';
3-
import JobManagementHeader from './JobManagementHeader';
43
import JobManagementTable from './JobManagementTable';
54
import { JobQuerySchemaType } from '@/lib/validators/jobs.validator';
65

@@ -13,10 +12,10 @@ const JobManagement = async ({
1312
if (!jobs.status) {
1413
return <div>Error {jobs.message}</div>;
1514
}
15+
1616
return (
17-
<div className="pt-2 px-6 mt-10">
18-
<JobManagementHeader />
19-
<JobManagementTable jobs={jobs} searchParams={searchParams} />
17+
<div>
18+
<JobManagementTable jobs={jobs.additional} searchParams={searchParams} />
2019
</div>
2120
);
2221
};

0 commit comments

Comments
 (0)