Skip to content

Commit 6dafb40

Browse files
Merge branch 'main' into resume
2 parents 5827ec4 + 4861a02 commit 6dafb40

5 files changed

Lines changed: 98 additions & 2 deletions

File tree

components/ShareButtons.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ interface ShareButtonsProps {
66
}
77

88
export default function ShareButtons({ url, title = '' }: ShareButtonsProps) {
9-
const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`;
10-
const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`;
9+
const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(
10+
url
11+
)}`;
12+
const twitterUrl =
13+
`https://x.com/intent/tweet?url=${encodeURIComponent(url)}` +
14+
(title ? `&text=${encodeURIComponent(title)}` : '');
1115

1216
return (
1317
<div className="flex gap-3">

lib/resume-parser.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,30 @@ function extractTextFromBuffer(buffer: Buffer, _mimeType: string): string {
118118
return printable;
119119
}
120120

121+
/**
122+
* Extracts a phone number from raw resume text.
123+
*
124+
* Matches common formats including international prefixes,
125+
* dashes, dots, spaces, and parentheses.
126+
*
127+
* @param text - Raw resume text.
128+
* @returns The first phone number found, or an empty string.
129+
*
130+
* @example
131+
* const phone = extractPhone(rawText);
132+
*/
133+
function extractPhone(text: string): string {
134+
const match = text.match(/(\+?\d{1,3}[\s.-]?)?(\(?\d{3}\)?[\s.-]?)(\d{3}[\s.-]?\d{4})/);
135+
return match ? match[0].trim() : '';
136+
}
137+
121138
export async function parseResume(buffer: Buffer, mimeType: string): Promise<ParsedResume> {
122139
const rawText = extractTextFromBuffer(buffer, mimeType);
123140

124141
return {
125142
name: extractName(rawText),
126143
email: extractEmail(rawText),
144+
phone: extractPhone(rawText),
127145
skills: extractSkills(rawText),
128146
education: extractEducation(rawText),
129147
experience: extractExperience(rawText),
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { Notification } from './Notification';
3+
4+
describe('Notification massive scaling behavior', () => {
5+
it('creates 1000 notification documents without throwing', () => {
6+
expect(() => {
7+
Array.from({ length: 1000 }, (_, i) => {
8+
return new Notification({
9+
username: `user${i}`,
10+
email: `user${i}@example.com`,
11+
});
12+
});
13+
}).not.toThrow();
14+
});
15+
16+
it('keeps default notification flags stable across many documents', () => {
17+
const notifications = Array.from({ length: 500 }, (_, i) => {
18+
return new Notification({
19+
username: `user${i}`,
20+
email: `user${i}@example.com`,
21+
});
22+
});
23+
24+
expect(notifications.every((n) => n.notifyOnCommit === true)).toBe(true);
25+
expect(notifications.every((n) => n.notifyOnStreak === true)).toBe(true);
26+
expect(notifications.every((n) => n.notifyOnMilestone === true)).toBe(true);
27+
expect(notifications.every((n) => n.isActive === true)).toBe(true);
28+
});
29+
30+
it('normalizes usernames and emails consistently under high volume', () => {
31+
const notifications = Array.from({ length: 300 }, (_, i) => {
32+
return new Notification({
33+
username: ` USER${i} `,
34+
email: ` USER${i}@EXAMPLE.COM `,
35+
});
36+
});
37+
38+
expect(notifications[0].username).toBe('user0');
39+
expect(notifications[0].email).toBe('user0@example.com');
40+
expect(notifications[299].username).toBe('user299');
41+
expect(notifications[299].email).toBe('user299@example.com');
42+
});
43+
44+
it('supports all allowed frequency values across many documents', () => {
45+
const frequencies = ['realtime', 'daily', 'weekly'] as const;
46+
47+
const notifications = Array.from({ length: 300 }, (_, i) => {
48+
return new Notification({
49+
username: `user${i}`,
50+
email: `user${i}@example.com`,
51+
frequency: frequencies[i % frequencies.length],
52+
});
53+
});
54+
55+
expect(notifications.filter((n) => n.frequency === 'realtime')).toHaveLength(100);
56+
expect(notifications.filter((n) => n.frequency === 'daily')).toHaveLength(100);
57+
expect(notifications.filter((n) => n.frequency === 'weekly')).toHaveLength(100);
58+
});
59+
60+
it('preserves date defaults across bulk-created documents', () => {
61+
const notifications = Array.from({ length: 200 }, (_, i) => {
62+
return new Notification({
63+
username: `user${i}`,
64+
email: `user${i}@example.com`,
65+
});
66+
});
67+
68+
expect(notifications.every((n) => n.createdAt instanceof Date)).toBe(true);
69+
expect(notifications.every((n) => n.updatedAt instanceof Date)).toBe(true);
70+
});
71+
});

types/student.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('types/student', () => {
2929
const parsedResume: ParsedResume = {
3030
name: 'Sonal Mittal',
3131
email: 'sonal@example.com',
32+
phone: '',
3233
skills: ['TypeScript', 'React'],
3334
education: [education],
3435
experience: [experience],
@@ -77,6 +78,7 @@ describe('types/student', () => {
7778
data: {
7879
name: 'Sonal Mittal',
7980
email: 'sonal@example.com',
81+
phone: '',
8082
skills: ['React'],
8183
education: [education],
8284
experience: [experience],

types/student.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export interface ParsedResume {
22
name: string;
33
email: string;
4+
phone: string;
45
skills: string[];
56
education: Education[];
67
experience: Experience[];

0 commit comments

Comments
 (0)