Skip to content

Commit 6c913f2

Browse files
authored
Refactor blog and project date metadata (#233)
* Refactor blog and project date metadata * fix wonky dates
1 parent 50f5fe3 commit 6c913f2

File tree

15 files changed

+256
-177
lines changed

15 files changed

+256
-177
lines changed

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const createJestConfig = nextJest({
77

88
// Add any custom config to be passed to Jest
99
const customJestConfig = {
10+
setupFiles: ['./jest.polyfills.js'],
1011
setupFilesAfterEnv: ['./jest.setup.js'],
1112
watchman: false,
1213
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work

jest.polyfills.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { ReadableStream, TransformStream } = require('stream/web');
2+
const { TextDecoder, TextEncoder } = require('util');
3+
4+
if (!global.TextEncoder) {
5+
global.TextEncoder = TextEncoder;
6+
}
7+
8+
if (!global.TextDecoder) {
9+
global.TextDecoder = TextDecoder;
10+
}
11+
12+
if (!global.ReadableStream) {
13+
global.ReadableStream = ReadableStream;
14+
}
15+
16+
if (!global.TransformStream) {
17+
global.TransformStream = TransformStream;
18+
}
19+
20+
if (!global.Request || !global.Response || !global.Headers || !global.fetch) {
21+
const {
22+
fetch,
23+
Request,
24+
Response,
25+
Headers,
26+
FormData,
27+
} = require('next/dist/compiled/@edge-runtime/primitives/fetch');
28+
29+
global.fetch = fetch;
30+
global.Request = Request;
31+
global.Response = Response;
32+
global.Headers = Headers;
33+
global.FormData = FormData;
34+
}

lib/helpers.ts

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,63 @@
11
import { IProject, IPost } from '../types/types';
22

3-
export const formatDate = (parent: IProject | IPost): string => {
4-
const months = [
5-
'January',
6-
'February',
7-
'March',
8-
'April',
9-
'May',
10-
'June',
11-
'July',
12-
'August',
13-
'September',
14-
'October',
15-
'November',
16-
'December',
17-
];
18-
const date: Date = new Date(parent.timeStamp);
19-
const month: string = months[date.getMonth()];
20-
const year = date.getFullYear();
21-
return `${month}, ${year}`;
3+
const months = [
4+
'January',
5+
'February',
6+
'March',
7+
'April',
8+
'May',
9+
'June',
10+
'July',
11+
'August',
12+
'September',
13+
'October',
14+
'November',
15+
'December',
16+
];
17+
18+
const parseMonthYear = ({ date }: Pick<IProject | IPost, 'date'>) => {
19+
const [monthText, yearText] = date.split('/');
20+
const month = Number(monthText);
21+
const year = Number(yearText);
22+
23+
return { month, year };
24+
};
25+
26+
export const formatDate = (parent: Pick<IProject | IPost, 'date'>): string => {
27+
const { month, year } = parseMonthYear(parent);
28+
29+
if (!Number.isInteger(month) || month < 1 || month > 12 || !Number.isInteger(year)) {
30+
throw new Error(`Invalid date metadata "${parent.date}". Expected MM/YYYY.`);
31+
}
32+
33+
const monthLabel = months[month - 1];
34+
return `${monthLabel}, ${year}`;
2235
};
2336

2437
export const byNewestFirst = (
25-
a: IProject | IPost,
26-
b: IProject | IPost
27-
): number => b.timeStamp - a.timeStamp;
38+
a: Pick<IProject | IPost, 'date'>,
39+
b: Pick<IProject | IPost, 'date'>
40+
): number => {
41+
const aParsed = parseMonthYear(a);
42+
const bParsed = parseMonthYear(b);
43+
44+
if (aParsed.year !== bParsed.year) {
45+
return bParsed.year - aParsed.year;
46+
}
47+
48+
return bParsed.month - aParsed.month;
49+
};
2850

2951
export const byOldestFirst = (
30-
a: IProject | IPost,
31-
b: IProject | IPost
32-
): number => a.timeStamp - b.timeStamp;
52+
a: Pick<IProject | IPost, 'date'>,
53+
b: Pick<IProject | IPost, 'date'>
54+
): number => {
55+
const aParsed = parseMonthYear(a);
56+
const bParsed = parseMonthYear(b);
57+
58+
if (aParsed.year !== bParsed.year) {
59+
return aParsed.year - bParsed.year;
60+
}
61+
62+
return aParsed.month - bParsed.month;
63+
};

lib/posts/postsService.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { byNewestFirst } from '../helpers';
44
export const postsData: IPost[] = [
55
{
66
slug: 'a-letter-to-my-pre-bootcamp-self',
7-
timeStamp: 1601009408032,
7+
date: '09/2020',
88
title: 'A letter to my pre-bootcamp self',
99
tags: ['Career', 'Learning', 'Reflection', 'Programming'],
1010
previewImgSrc: '/images/blog/a-letter.png',
@@ -14,7 +14,7 @@ export const postsData: IPost[] = [
1414
},
1515
{
1616
slug: 'hunting-with-my-father',
17-
timeStamp: 1596009408032,
17+
date: '07/2019',
1818
title: 'Hunting With My Father',
1919
tags: ['Family', 'Hunting', 'Outdoors'],
2020
previewImgSrc: '/images/blog/hunting-w-my-father.jpg',
@@ -24,7 +24,7 @@ export const postsData: IPost[] = [
2424
},
2525
{
2626
slug: 'just-the-right-thing',
27-
timeStamp: 1563009408032,
27+
date: '07/2019',
2828
title: 'Just the Right Thing',
2929
tags: ['Mindset', 'Reflection', 'Work'],
3030
previewImgSrc:
@@ -35,7 +35,7 @@ export const postsData: IPost[] = [
3535
},
3636
{
3737
slug: 'maf',
38-
timeStamp: 1554009408032,
38+
date: '03/2019',
3939
title: 'M.A.F.',
4040
tags: ['Health', 'Learning', 'Running'],
4141
previewImgSrc: '/images/blog/MAF/MAFTestInitial.jpg',
@@ -45,7 +45,7 @@ export const postsData: IPost[] = [
4545
},
4646
{
4747
slug: 'one-really-well-written-paragraph',
48-
timeStamp: 1563009408032,
48+
date: '07/2019',
4949
title: 'One Really Well-Written Paragraph',
5050
tags: ['Learning', 'Reflection', 'Writing'],
5151
previewImgSrc: '/images/blog/one-paragraph.jpg',
@@ -55,7 +55,7 @@ export const postsData: IPost[] = [
5555
},
5656
{
5757
slug: 'ritual',
58-
timeStamp: 1580438545989,
58+
date: '01/2020',
5959
title: 'Ritual',
6060
tags: ['Outdoors', 'Hunting'],
6161
previewImgSrc: '/images/blog/ritual/ritual-2.jpg',
@@ -65,7 +65,7 @@ export const postsData: IPost[] = [
6565
},
6666
{
6767
slug: 'most-important-question',
68-
timeStamp: 1593438545989,
68+
date: '06/2019',
6969
title: 'The Most Important Question',
7070
tags: ['Mindset', 'Reflection'],
7171
previewImgSrc: '/images/blog/MIQ.jpg',
@@ -74,7 +74,7 @@ export const postsData: IPost[] = [
7474
},
7575
{
7676
slug: 'where-is-the-fear',
77-
timeStamp: 1563009408032,
77+
date: '07/2019',
7878
title: 'Where is the Fear?',
7979
tags: ['Creativity', 'Mindset', 'Writing'],
8080
previewImgSrc: '/images/blog/where-is-the-fear.jpg',
@@ -84,7 +84,7 @@ export const postsData: IPost[] = [
8484
},
8585
{
8686
slug: 'worn-out-boots',
87-
timeStamp: 1569009408032,
87+
date: '09/2019',
8888
title: 'Worn Out Boots',
8989
tags: ['Hunting', 'Outdoors', 'Reflection'],
9090
previewImgSrc: '/images/blog/newboots.jpg',
@@ -94,7 +94,7 @@ export const postsData: IPost[] = [
9494
},
9595
{
9696
slug: 'go-lang',
97-
timeStamp: 1667486292000,
97+
date: '11/2022',
9898
title: 'What I Learned from Learning GoLang',
9999
tags: ['Career', 'Learning', 'Programming'],
100100
componentName: 'LearningGolang',

lib/projects/projectsData.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const projects: IProject[] = [
1616
{
1717
slug: 'day-tracker',
1818
title: 'Day Tracker',
19-
timeStamp: 1580285311842, // January
19+
date: '01/2020',
2020
description:
2121
'Day Tracker is a free time-logging tool that tracks and displays how the user spends his or her time throughout a given day. This web-based app was my showcase project for my FEWD course taken through General Assembly.',
2222
tech: [
@@ -35,7 +35,7 @@ export const projects: IProject[] = [
3535
{
3636
slug: 'battleship',
3737
title: 'Battleship',
38-
timeStamp: 1590810545989, // May
38+
date: '05/2020',
3939
description:
4040
"This version of Battleship is based on the popular children's board game. Play against the computer to locate and sink its ships, before it sinks all of yours!",
4141
tech: ['HTML', 'CSS', 'JavaScript'],
@@ -46,7 +46,7 @@ export const projects: IProject[] = [
4646
{
4747
slug: 'outdoor-journal',
4848
title: 'Outdoor Journal',
49-
timeStamp: 1590810545989, // May
49+
date: '05/2020',
5050
description:
5151
'The Outdoor Journal is a MEN stack app that helps you plan, record, and save memories of your favorite outdoor adventures. This project was born out of my own personal experience as an avid outdoorsman and journal keeper.',
5252
tech: [
@@ -65,7 +65,7 @@ export const projects: IProject[] = [
6565
{
6666
slug: 'finch-finder',
6767
title: 'Finch Finder',
68-
timeStamp: 1593438545989, // June
68+
date: '06/2020',
6969
description:
7070
"For years, I've been a casual birder. There are tons of great apps out there for looking up and tracking birds, but I wanted to make one that fit my specific needs. Enjoy!",
7171
tech: [
@@ -84,7 +84,7 @@ export const projects: IProject[] = [
8484
{
8585
slug: 'gas-app',
8686
title: 'GASapp',
87-
timeStamp: 1593438545989, // June
87+
date: '06/2020',
8888
description:
8989
'Music enthusiasts often suffer from something called GAS - "Gear Acquisition Syndrome." The GASapp is a place where you can store and evaluate all of your music gear in one easy to access list. The app includes valuations on each piece of gear you own, or a price listing on your wish-list items (thanks to the Reverb.com API).',
9090
collaborators: [collaborators[0], collaborators[1]],
@@ -105,7 +105,7 @@ export const projects: IProject[] = [
105105
{
106106
slug: 'obnoxious',
107107
title: 'obNoxious',
108-
timeStamp: 1596066545989, // July
108+
date: '07/2020',
109109
description:
110110
'Invasive species are an issue worldwide, but this app focuses on those species invading North America, specifically the United States. The obNoxious app servers two purposes:',
111111
subDescription: [
@@ -129,7 +129,7 @@ export const projects: IProject[] = [
129129
{
130130
slug: 'traviscashiondotcom',
131131
title: 'TravisCashion.com (v2.0)',
132-
timeStamp: 1639754698396, // December 2021
132+
date: '12/2021',
133133
description:
134134
'This is the second iteration of my personal portfolio site. This site runs on NextJS, which is a React-based framework that serves fast, highly performant React sites.',
135135
tech: [
@@ -146,7 +146,7 @@ export const projects: IProject[] = [
146146
{
147147
slug: 'stopanalyzing',
148148
title: 'Stop Analyzing Embed (open source)',
149-
timeStamp: 1597471200000, // August
149+
date: '08/2020',
150150
description:
151151
'Stop Analyzing Embed is a beginner-friendly, open source project created and maintained by Banco Do Brasil. Think of it like a Tinder app for products: the user compares two products presented on cards, and chooses the one that they like most. I contributed to this project in two ways. First, I re-wrote the documentation to correct typos and make the information more accessible to beginner developers. Then, I created a button component, complete with Jest units tests, that triggers and animation to slide the cards off of the screen (in the event that the user does not like either option presented).',
152152
tech: [
@@ -165,7 +165,7 @@ export const projects: IProject[] = [
165165
// {
166166
// slug: 'vuex-webextensions',
167167
// title: 'Vuex Webextensions (open source)',
168-
// timeStamp: 0,
168+
// date: 'MM/YYYY',
169169
// description: '',
170170
// tech: [],
171171
// githubUrl: '',
@@ -174,7 +174,7 @@ export const projects: IProject[] = [
174174
// {
175175
// slug: 'chromedriver',
176176
// title: 'Selenium Chromedriver (open source)',
177-
// timeStamp: 0,
177+
// date: 'MM/YYYY',
178178
// description: '',
179179
// tech: [],
180180
// githubUrl: '',
@@ -183,7 +183,7 @@ export const projects: IProject[] = [
183183
{
184184
slug: 'bex',
185185
title: 'Ibotta Browser Extension (Contributor)',
186-
timeStamp: 1639754699396, // December 2021,
186+
date: '12/2021',
187187
description:
188188
"Get cash back at your favorite stores with the help of Ibotta's browser extension.",
189189
tech: [
@@ -203,7 +203,7 @@ export const projects: IProject[] = [
203203
{
204204
slug: 'leftover-tag-scraper',
205205
title: 'Leftover Tag Scraper',
206-
timeStamp: 1699538699396, // November 2023
206+
date: '11/2023',
207207
description:
208208
"Scrape the Colorado Parks and Wildlife leftover tag list to find out what's available. Then, send an email to subscribers using Twilio's SendGrid platform.",
209209
tech: [
@@ -216,11 +216,10 @@ export const projects: IProject[] = [
216216
githubUrl: PRIVATE,
217217
previewImgSrc: '/images/portfolio/previews/leftover-tag-scraper.png',
218218
},
219-
// monarch extension, timestamp July 1, 2024
220219
{
221220
slug: 'monarch',
222221
title: 'Caterpillar Browser Extension',
223-
timeStamp: 1736222718396, // January 2025
222+
date: '01/2025',
224223
description:
225224
'Caterpillar is a browser extension extension designed to extend the capabilities of the Monarch Financial website. Specifically, the extension scrapes your Amazon orders page in order to help users categorize Amazon purchases in Monarch. This project is available to the public on the Chrome web store.',
226225
tech: ['React', 'TypeScript', 'NextJs'],

lib/projects/projectsService.ts

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
import { IProject } from '../../types/types';
2+
import { byNewestFirst } from '../helpers';
23
import { projects } from './projectsData';
34

4-
export const getAllProjects = (): IProject[] => {
5-
return projects
6-
.sort((a, b) => {
7-
if (a.timeStamp < b.timeStamp) {
8-
return 1;
9-
} else {
10-
return -1;
11-
}
12-
})
13-
.map((project) => ({
14-
...project,
15-
date: formatProjectDate(project),
16-
}));
17-
};
5+
export const getAllProjects = (): IProject[] => [...projects].sort(byNewestFirst);
186

197
export const getAllProjectSlugs = (): string[] => {
208
const projectSlugs = projects.map((project) => project.slug);
@@ -25,24 +13,3 @@ export const getOneProjectData = (slug: string): IProject | undefined => {
2513
const project = projects.find((project) => project.slug === slug);
2614
return project;
2715
};
28-
29-
export const formatProjectDate = (project: IProject): string => {
30-
const months = [
31-
'January',
32-
'February',
33-
'March',
34-
'April',
35-
'May',
36-
'June',
37-
'July',
38-
'August',
39-
'September',
40-
'October',
41-
'November',
42-
'December',
43-
];
44-
const date: Date = new Date(project.timeStamp);
45-
const month: string = months[date.getMonth()];
46-
const year = date.getFullYear();
47-
return `${month}, ${year}`;
48-
};

0 commit comments

Comments
 (0)