Skip to content

Commit a625278

Browse files
change countdown due date time + fix overflow scrolling for applicant… (#216)
* change countdown due date time + fix overflow scrolling for applicant/admin main page views * changed script gen to match google form + spacing issue
1 parent bd222a4 commit a625278

File tree

9 files changed

+214
-74
lines changed

9 files changed

+214
-74
lines changed

apps/backend/scripts/seed-mock-data.ts

Lines changed: 123 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ const REVIEW_STATUS_VALUES = Object.values(ReviewStatus);
7474
const POSITIONS = Object.values(Position);
7575
const SEMESTER_DEFAULT = Semester.SPRING;
7676
const YEAR_DEFAULT = 2026;
77+
const REVIEW_COMMENTS = [
78+
'Strong analytical breakdown with measurable success metrics.',
79+
'Creative approach to ambiguous prompts and thoughtful user empathy.',
80+
'Great initiative but would like deeper dives into tradeoffs.',
81+
'Excellent presentation polish and storytelling under time pressure.',
82+
'Solid collaboration signals; digs into blockers proactively.',
83+
'Needs more rigor around experimentation but strategy instincts are sound.',
84+
'Powerful technical depth with clean architecture diagrams.',
85+
'Great culture add with emphasis on mentoring and peer support.',
86+
];
87+
const REVIEW_FOCUS_AREAS = [
88+
'product sense',
89+
'execution',
90+
'communication',
91+
'technical depth',
92+
'user research',
93+
'data fluency',
94+
'leadership',
95+
];
96+
const DAY_IN_MS = 24 * 60 * 60 * 1000;
97+
const ROLE_LABELS: Record<Position, string> = {
98+
[Position.DEVELOPER]: 'Developer',
99+
[Position.PM]: 'Product Manager',
100+
[Position.DESIGNER]: 'Designer',
101+
};
77102

78103
async function main() {
79104
const envLoaded = loadEnvIfPresent('../.env');
@@ -120,9 +145,10 @@ async function main() {
120145
users,
121146
config.personalUser,
122147
);
148+
const reviews = await seedReviews(dataSource, applications, users);
123149

124150
console.log(
125-
`Seed complete. Inserted ${users.length} users and ${applications.length} applications.`,
151+
`Seed complete. Inserted ${users.length} users, ${applications.length} applications, and ${reviews.length} reviews.`,
126152
);
127153
} catch (error) {
128154
console.error('Mock data seed failed:', error);
@@ -231,16 +257,7 @@ async function seedApplications(
231257
const createdAt = new Date(
232258
Date.UTC(YEAR_DEFAULT, (index * 3) % 12, (index % 27) + 1, 12, 0, 0),
233259
);
234-
const response: Response[] = [
235-
{
236-
question: 'Why do you want to work on this role?',
237-
answer: `I am excited to contribute as a ${position} during the ${semester} semester.`,
238-
},
239-
{
240-
question: 'What stage best suits you right now?',
241-
answer: `Currently focused on ${stage} with ${stageProgress} progress.`,
242-
},
243-
];
260+
const response = buildApplicationResponses(owner, position);
244261

245262
return appRepo.create({
246263
user: owner,
@@ -268,17 +285,7 @@ async function seedApplications(
268285
stage: ApplicationStage.PM_CHALLENGE,
269286
stageProgress: StageProgress.PENDING,
270287
reviewStatus: ReviewStatus.UNASSIGNED,
271-
response: [
272-
{
273-
question: 'Who owns this application?',
274-
answer: `${personalUser.firstName} ${personalUser.lastName} (${personalUser.email}).`,
275-
},
276-
{
277-
question: 'Why is this record seeded?',
278-
answer:
279-
'This hardcoded row is appended for the personal user defined in seed.config.json.',
280-
},
281-
],
288+
response: buildApplicationResponses(personalUser, Position.PM),
282289
assignedRecruiterIds:
283290
recruiterIds.length === 0
284291
? []
@@ -292,6 +299,100 @@ async function seedApplications(
292299
return appRepo.save(applications);
293300
}
294301

302+
async function seedReviews(
303+
dataSource: DataSource,
304+
applications: Application[],
305+
users: User[],
306+
): Promise<Review[]> {
307+
const reviewRepo = dataSource.getRepository(Review);
308+
const recruiterMap = new Map<number, User>(
309+
users
310+
.filter((user) => user.status === UserStatus.RECRUITER)
311+
.map((recruiter) => [recruiter.id, recruiter]),
312+
);
313+
314+
const reviews: Review[] = [];
315+
316+
applications.forEach((application, index) => {
317+
const assigned = application.assignedRecruiterIds ?? [];
318+
if (!assigned.length) {
319+
return;
320+
}
321+
322+
const reviewCount = index % 3; // cycle through 0, 1, 2 reviews per applicant
323+
324+
for (let offset = 0; offset < reviewCount; offset++) {
325+
const reviewerId = assigned[(index + offset) % assigned.length];
326+
const reviewer = recruiterMap.get(reviewerId);
327+
if (!reviewer) {
328+
continue;
329+
}
330+
331+
const stage =
332+
APPLICATION_STAGES[
333+
(index + reviewerId + offset) % APPLICATION_STAGES.length
334+
];
335+
const ratingBase =
336+
1 + ((index * 17 + reviewerId * 13 + offset * 7) % 40) / 10;
337+
const rating = Number(Math.min(5, ratingBase).toFixed(1));
338+
const commentSeed =
339+
(index + reviewerId + offset) % REVIEW_COMMENTS.length;
340+
const focus =
341+
REVIEW_FOCUS_AREAS[(index + offset) % REVIEW_FOCUS_AREAS.length];
342+
const content = `${REVIEW_COMMENTS[commentSeed]} Focused on ${focus} for the ${application.position} track.`;
343+
const baseDate = application.createdAt
344+
? new Date(application.createdAt)
345+
: new Date(Date.UTC(YEAR_DEFAULT, 0, 1));
346+
const createdAt = new Date(baseDate.getTime() + (offset + 1) * DAY_IN_MS);
347+
348+
reviews.push(
349+
reviewRepo.create({
350+
application,
351+
reviewer,
352+
reviewerId,
353+
rating,
354+
stage,
355+
content,
356+
createdAt,
357+
updatedAt: createdAt,
358+
}),
359+
);
360+
}
361+
});
362+
363+
console.log(`Generating ${reviews.length} review rows...`);
364+
if (!reviews.length) {
365+
return [];
366+
}
367+
368+
return reviewRepo.save(reviews);
369+
}
370+
371+
function buildApplicationResponses(
372+
owner: User,
373+
position: Position,
374+
): Response[] {
375+
return [
376+
{
377+
question: 'Full Name',
378+
answer: buildFullName(owner),
379+
},
380+
{
381+
question: 'Email',
382+
answer: owner.email,
383+
},
384+
{
385+
question: 'Role',
386+
answer: ROLE_LABELS[position],
387+
},
388+
];
389+
}
390+
391+
function buildFullName(user: User): string {
392+
const name = [user.firstName, user.lastName].filter(Boolean).join(' ').trim();
393+
return name || 'Unknown Applicant';
394+
}
395+
295396
function buildNamePairs(): Array<{ firstName: string; lastName: string }> {
296397
const pairs: Array<{ firstName: string; lastName: string }> = [];
297398
FIRST_NAMES.forEach((firstName) => {

apps/backend/src/applications/applications.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ export class ApplicationsService {
7373

7474
// Determine position from provided role (if any). Default to DEVELOPER.
7575
let positionEnum = Position.DEVELOPER;
76-
this.logger.debug(`submitApp called with role='${role}' for user ${user.email}`);
76+
this.logger.debug(
77+
`submitApp called with role='${role}' for user ${user.email}`,
78+
);
7779
if (role) {
7880
const r = (role || '').toString().toUpperCase();
7981
if (r === 'PM' || r === 'PRODUCT_MANAGER' || r === 'PRODUCT MANAGER') {

apps/frontend/src/features/applicant/components/ApplicantView/user.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export const ApplicantView = ({ user }: ApplicantViewProps) => {
9595
borderRadius: 2,
9696
boxShadow: 2,
9797
width: { xs: '95%', md: '70%' },
98-
maxWidth: 900,
98+
maxWidth: 700,
9999
position: 'relative',
100100
zIndex: 1,
101101
boxSizing: 'border-box',

apps/frontend/src/features/applications/components/ApplicationTables/index.tsx

Lines changed: 78 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getRecruitmentYear as getCurrentYear,
1515
} from '@sharedTypes/utils/cycle';
1616
import {
17+
dataGridStyles,
1718
defaultPaginationModel,
1819
defaultPageSizeOptions,
1920
} from '@styles/dataGridTheme';
@@ -32,49 +33,84 @@ export function ApplicationTable() {
3233
const showEmpty = !isLoading && !error && data.length === 0;
3334

3435
return (
35-
<Container maxWidth="xl">
36-
<Stack direction="row" alignItems="center" spacing={2} mt={4} mb={8}>
37-
<img
38-
src={LOGO_PATHS.SQUARE}
39-
alt="C4C Logo"
40-
style={{ width: 50, height: 40 }}
41-
/>
42-
<Typography variant="h4" sx={{ fontWeight: 'bold', color: 'white' }}>
43-
Database | {getCurrentSemester()} {getCurrentYear()} Recruitment Cycle
44-
</Typography>
45-
</Stack>
46-
{showEmpty ? (
47-
<Box
48-
sx={{
49-
display: 'flex',
50-
alignItems: 'center',
51-
justifyContent: 'center',
52-
height: 300,
53-
border: '1px dashed rgba(255,255,255,0.2)',
54-
borderRadius: 2,
55-
color: 'rgba(255,255,255,0.85)',
56-
background: 'rgba(255,255,255,0.02)',
57-
}}
36+
<Box
37+
sx={{
38+
minHeight: '100vh',
39+
backgroundColor: '#181818',
40+
overflow: 'hidden',
41+
display: 'flex',
42+
flexDirection: 'column',
43+
}}
44+
>
45+
<Container
46+
maxWidth="xl"
47+
sx={{
48+
flex: 1,
49+
display: 'flex',
50+
flexDirection: 'column',
51+
gap: 4,
52+
py: 4,
53+
minHeight: 0,
54+
}}
55+
>
56+
<Stack
57+
direction="row"
58+
alignItems="center"
59+
spacing={2}
60+
sx={{ flexShrink: 0 }}
5861
>
59-
<Typography variant="h6" sx={{ fontWeight: 500 }}>
60-
There are no applications at this time
62+
<img
63+
src={LOGO_PATHS.SQUARE}
64+
alt="C4C Logo"
65+
style={{ width: 50, height: 40 }}
66+
/>
67+
<Typography variant="h4" sx={{ fontWeight: 'bold', color: 'white' }}>
68+
Database | {getCurrentSemester()} {getCurrentYear()} Recruitment
69+
Cycle
6170
</Typography>
62-
</Box>
63-
) : (
64-
<DataGrid
65-
rows={data}
66-
columns={applicationColumns(allRecruiters)}
67-
initialState={{
68-
pagination: {
69-
paginationModel: defaultPaginationModel,
70-
},
71-
}}
72-
pageSizeOptions={defaultPageSizeOptions}
73-
onRowClick={handleRowClick}
74-
disableRowSelectionOnClick
75-
sx={{ cursor: 'pointer' }}
76-
/>
77-
)}
78-
</Container>
71+
</Stack>
72+
73+
{showEmpty ? (
74+
<Box
75+
sx={{
76+
flex: 1,
77+
minHeight: 0,
78+
display: 'flex',
79+
alignItems: 'center',
80+
justifyContent: 'center',
81+
border: '1px dashed rgba(255,255,255,0.2)',
82+
borderRadius: 2,
83+
color: 'rgba(255,255,255,0.85)',
84+
background: 'rgba(255,255,255,0.02)',
85+
}}
86+
>
87+
<Typography variant="h6" sx={{ fontWeight: 500 }}>
88+
There are no applications at this time
89+
</Typography>
90+
</Box>
91+
) : (
92+
<Box sx={{ flex: 1, minHeight: 0 }}>
93+
<DataGrid
94+
rows={data}
95+
columns={applicationColumns(allRecruiters)}
96+
initialState={{
97+
pagination: {
98+
paginationModel: defaultPaginationModel,
99+
},
100+
}}
101+
pageSizeOptions={defaultPageSizeOptions}
102+
onRowClick={handleRowClick}
103+
disableRowSelectionOnClick
104+
sx={{
105+
...dataGridStyles,
106+
cursor: 'pointer',
107+
height: '100%',
108+
width: '100%',
109+
}}
110+
/>
111+
</Box>
112+
)}
113+
</Container>
114+
</Box>
79115
);
80116
}

apps/frontend/src/features/applications/components/ApplicationTables/individualApplication.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ const IndividualApplicationDetails = ({
403403
)}
404404
</Grid>
405405

406-
<Grid container spacing={1.5}>
406+
<Grid container spacing={1.5} sx={{ mt: 2 }}>
407407
<Grid item xs={12} md={8}>
408408
<Stack
409409
direction="column"
@@ -413,7 +413,6 @@ const IndividualApplicationDetails = ({
413413
p: { xs: 2, md: 2.5 },
414414
backgroundColor: 'transparent',
415415
gap: 1,
416-
mt: 2,
417416
}}
418417
>
419418
<Typography

apps/frontend/src/features/homepage/components/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const Header = ({ isAuthenticated, onSignOut }: HeaderProps) => {
2929
style={{ height: '40px', width: 'auto' }}
3030
/>
3131
<Typography variant="h5" sx={{ fontWeight: 500 }}>
32-
2025 Application
32+
2026 Application
3333
</Typography>
3434
</Box>
3535

apps/frontend/src/shared/pages/HomePage.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const HomePage = () => {
2323
const { isAuthenticated, signOut } = useAuth();
2424

2525
// Application deadline
26-
const deadline = new Date('2025-10-31T23:59:59');
26+
const deadline = new Date('2026-01-01T23:59:59');
2727

2828
return (
2929
<Box
@@ -36,8 +36,8 @@ const HomePage = () => {
3636
>
3737
<Header isAuthenticated={isAuthenticated} onSignOut={signOut} />
3838

39-
<Container maxWidth="md" sx={{ flex: 1, py: 8 }}>
40-
<Stack spacing={4}>
39+
<Container maxWidth="md" sx={{ py: 3 }}>
40+
<Stack spacing={2}>
4141
<WelcomeBanner />
4242
<RoleSelector />
4343
<DeadlineCountdown deadline={deadline} />
@@ -46,5 +46,4 @@ const HomePage = () => {
4646
</Box>
4747
);
4848
};
49-
5049
export default HomePage;

apps/frontend/src/styles.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ html, body {
44
-webkit-font-smoothing: antialiased;
55
-moz-osx-font-smoothing: grayscale;
66
min-height: 100vh;
7+
margin: 0;
8+
padding: 0;
9+
overflow-x: hidden;
710
}
811

912
#root {

0 commit comments

Comments
 (0)