-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add remaining changes for last commit
- Loading branch information
Showing
35 changed files
with
785 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import type { ArticleFormData } from '@app/types'; | ||
|
||
export const newArticleFormTemplate: ArticleFormData = { | ||
title: '', | ||
body: '', | ||
imageId: null, | ||
isSticky: false, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import moment from 'moment-timezone'; | ||
|
||
import type { EventFormData } from '@app/types'; | ||
|
||
export const newEventFormTemplate: EventFormData = { | ||
type: 'blitz tournament', | ||
eventDate: moment() | ||
.tz('America/Toronto', false) | ||
.set('hours', 18) | ||
.set('minutes', 0) | ||
.toISOString(), | ||
title: '', | ||
details: '', | ||
articleId: '', | ||
}; |
18 changes: 18 additions & 0 deletions
18
src/app/components/member-form/new-member-form-template.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import moment from 'moment-timezone'; | ||
|
||
import type { MemberFormData } from '@app/types'; | ||
|
||
export const newMemberFormTemplate: MemberFormData = { | ||
firstName: '', | ||
lastName: '', | ||
city: 'London', | ||
rating: '1000/0', | ||
peakRating: '1000/0', | ||
dateJoined: moment().toISOString(), | ||
isActive: true, | ||
chesscomUsername: '', | ||
lichessUsername: '', | ||
yearOfBirth: '', | ||
email: '', | ||
phoneNumber: '', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { camelCase } from 'lodash'; | ||
|
||
import { Pipe, PipeTransform } from '@angular/core'; | ||
|
||
/** | ||
* Convert string to camel-case; return `''` if invalid string provided. | ||
*/ | ||
@Pipe({ | ||
name: 'camelCase', | ||
}) | ||
export class CamelCasePipe implements PipeTransform { | ||
transform(value: unknown): string { | ||
return typeof value === 'string' ? camelCase(value) : ''; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export { CamelCasePipe } from './camel-case.pipe'; | ||
export { FormatBytesPipe } from './format-bytes.pipe'; | ||
export { FormatDatePipe } from './format-date.pipe'; | ||
export { KebabCasePipe } from './kebab-case.pipe'; | ||
export { RangePipe } from './range.pipe'; | ||
export { RouterLinkPipe } from './router-link.pipe'; | ||
export { StripMarkdownPipe } from './strip-markdown.pipe'; | ||
export { TruncateByCharsPipe } from './truncate-by-chars.pipe'; | ||
export { WasEditedPipe } from './was-edited.pipe'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { kebabCase } from 'lodash'; | ||
|
||
import { Pipe, PipeTransform } from '@angular/core'; | ||
|
||
/** | ||
* Convert string to kebab-case; return `''` if invalid string provided. | ||
*/ | ||
@Pipe({ | ||
name: 'kebabCase', | ||
}) | ||
export class KebabCasePipe implements PipeTransform { | ||
transform(value: unknown): string { | ||
return typeof value === 'string' ? kebabCase(value) : ''; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Pipe, PipeTransform } from '@angular/core'; | ||
|
||
import type { InternalPath } from '@app/types'; | ||
|
||
/** | ||
* Parse potential InternalPath tuple and add '/' prefix for Angular's routerLink. | ||
*/ | ||
@Pipe({ | ||
name: 'routerLink', | ||
}) | ||
export class RouterLinkPipe implements PipeTransform { | ||
transform(path: InternalPath | string): string { | ||
const fullPath = Array.isArray(path) ? path.join('/') : path; | ||
return '/' + fullPath; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import moment from 'moment-timezone'; | ||
|
||
import { Pipe, PipeTransform } from '@angular/core'; | ||
|
||
import type { ModificationInfo } from '@app/types'; | ||
import { isValidIsoDate } from '@app/utils'; | ||
|
||
/** | ||
* Check whether dateLastEdited and dateCreated properties on a ModificationInfo object are the same | ||
* to some level of granularity (defaults to `'day'`). | ||
* | ||
* Return `null` if modification info is `null` or `undefined`, or if either date is not a valid | ||
* ISO 8601 date string. | ||
*/ | ||
@Pipe({ | ||
name: 'wasEdited', | ||
}) | ||
export class WasEditedPipe implements PipeTransform { | ||
transform( | ||
modificationInfo?: ModificationInfo | null, | ||
granularity: moment.unitOfTime.StartOf = 'day', | ||
): boolean | null { | ||
if ( | ||
!modificationInfo || | ||
!isValidIsoDate(modificationInfo.dateCreated) || | ||
!isValidIsoDate(modificationInfo.dateLastEdited) | ||
) { | ||
return null; | ||
} | ||
|
||
return moment(modificationInfo.dateLastEdited).isSame( | ||
modificationInfo.dateCreated, | ||
granularity, | ||
); | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
const navPaths = [ | ||
'', | ||
'about', | ||
'members', | ||
'member', | ||
'schedule', | ||
'event', | ||
'news', | ||
'article', | ||
'city-champion', | ||
'photo-gallery', | ||
'game-archives', | ||
'documents', | ||
'login', | ||
'logout', | ||
'change-password', | ||
] as const; | ||
export type NavPath = (typeof navPaths)[number]; | ||
|
||
export function isNavPath(value: unknown): value is NavPath { | ||
return navPaths.indexOf(value as NavPath) !== -1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { isDefined } from '@app/utils'; | ||
|
||
/** | ||
* Check whether a `localStorage` or `sessionStorage` is supported. | ||
* | ||
* Browsers can make the storage not accessible in different ways, such as not exposing it at all | ||
* on the global object, or throwing errors as soon as it's attempted to be accessed. To account | ||
* for all these cases, try to store a dummy item using a try & catch to analyze the thrown error. | ||
* | ||
* @param webStorageType The Web Storage API to check | ||
*/ | ||
export function isStorageSupported( | ||
webStorageType: 'localStorage' | 'sessionStorage' = 'localStorage', | ||
): boolean { | ||
let storage: Storage | undefined; | ||
|
||
try { | ||
storage = window[webStorageType]; | ||
|
||
if (!storage) { | ||
return false; | ||
} | ||
|
||
const x = '__storage_test__'; | ||
storage.setItem(x, x); | ||
storage.removeItem(x); | ||
|
||
return true; | ||
} catch (error) { | ||
// Acknowledge a QuotaExceededError only if there's something already stored | ||
const isValidQuotaExceededError = | ||
isDefined(storage) && | ||
error instanceof DOMException && | ||
(error.code === 22 || | ||
error.code === 1014 || | ||
error.name === 'QuotaExceededError' || | ||
error.name === 'NS_ERROR_DOM_QUOTA_REACHED'); | ||
|
||
return isValidQuotaExceededError; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { isEqual, mapValues } from 'lodash'; | ||
|
||
/** | ||
* Check whether two objects are (deeply) equal. | ||
* | ||
* @param a The first object to compare | ||
* @param b The second object to compare | ||
* @param strict Treat null, undefined and empty string property values as unique | ||
*/ | ||
export function areSame(a: unknown, b: unknown, strict: boolean = false): boolean { | ||
if (a === null && b === null) { | ||
return true; | ||
} | ||
|
||
if (a === null || b === null) { | ||
return false; | ||
} | ||
|
||
if (!strict) { | ||
a = mapValues(a, value => (value === undefined || value === '' ? null : value)); | ||
b = mapValues(b, value => (value === undefined || value === '' ? null : value)); | ||
} | ||
|
||
return isEqual(a, b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* Narrow down type of T by removing `null` and `undefined`. | ||
*/ | ||
export function isDefined<T>(value: T & unknown): value is NonNullable<T> { | ||
return value !== null && value !== undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* Take N-number random items from an array if N defined; otherwise return the full array. | ||
* | ||
* @param array The array (any type) | ||
* @param n The number of items to take | ||
*/ | ||
export function takeRandomly<T>(array: T[], n?: number): T[] { | ||
return array.sort(() => 0.5 - Math.random()).slice(0, n ?? array?.length ?? 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* Check whether value is a valid MongoDB ID (used for identifying articles, events and members). | ||
*/ | ||
export function isValidCollectionId(value: unknown): boolean { | ||
return typeof value === 'string' && /^[a-f\d]{24}$/.test(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import moment from 'moment-timezone'; | ||
|
||
import type { IsoDate } from '@app/types'; | ||
|
||
/** | ||
* Convert ISO8601 date string (`YYYY-MM-DDTHH:mm:ss`) to one of the following formats: | ||
* * `long`: Thursday, January 1st 2024 at 6:00 PM (default) | ||
* * `long no-time`: Thursday, January 1st 2024 | ||
* * `short`: Thu, Jan 1, 2024, 6:00 PM | ||
* * `short no-time`: Thu, Jan 1, 2024 | ||
* Timezone automatically displayed as EST/EDT due to default timezone set in root App Component. | ||
* | ||
* Return `'Invalid date'` if date provided is undefined or has invalid ISO860 format. | ||
*/ | ||
export function formatDate( | ||
date?: IsoDate, | ||
format: 'long' | 'long no-time' | 'short' | 'short no-time' = 'long', | ||
): string { | ||
switch (format) { | ||
case 'long': | ||
return moment(date).format('dddd, MMMM Do YYYY [at] h:mm A'); | ||
case 'long no-time': | ||
return moment(date).format('dddd, MMMM Do YYYY'); | ||
case 'short': | ||
return moment(date).format('ddd, MMM D, YYYY, h:mm A'); | ||
case 'short no-time': | ||
return moment(date).format('ddd, MMM D, YYYY'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import moment from 'moment-timezone'; | ||
|
||
/** | ||
* Check whether value is a valid ISO 8601 date string (i.e. in the form of `YYYY-MM-DDTHH:mm:ss`). | ||
*/ | ||
export function isValidIsoDate(value: unknown): boolean { | ||
return typeof value === 'string' && moment(value, moment.ISO_8601, true).isValid(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* Check whether value is a valid time, formatted as `hh:mm A` | ||
* (e.g. `5:45 PM`, `6:00 am`, or `12:00 PM`). | ||
*/ | ||
export function isValidTime(value: unknown): boolean { | ||
return ( | ||
typeof value === 'string' && | ||
/^([1-9]|0[1-9]|1[0-2]):[0-5][0-9] ([AP][Mm]|[ap]m)$/.test(value) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { HttpErrorResponse } from '@angular/common/http'; | ||
|
||
/** | ||
* Convert 0-status errors to standard 500-status server errors; otherwise return unchanged. | ||
* | ||
* @param {HttpErrorResponse} response | ||
*/ | ||
export function parseHttpErrorResponse(response: HttpErrorResponse): HttpErrorResponse { | ||
if (response.status !== 0) { | ||
return response; | ||
} | ||
|
||
return { | ||
...response, | ||
status: 500, | ||
error: 'Unknown server error.', | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Url } from '@app/types'; | ||
|
||
/** | ||
* Convert a data URL (base-64 string) of a File to a Blob representing the same data. | ||
*/ | ||
export function dataUrlToBlob(dataUrl: Url): Blob { | ||
const byteString = atob(dataUrl.split(',')[1]); | ||
const arrayBuffer = new ArrayBuffer(byteString.length); | ||
const int8Array = new Uint8Array(arrayBuffer); | ||
|
||
for (let i = 0; i < byteString.length; i++) { | ||
int8Array[i] = byteString.charCodeAt(i); | ||
} | ||
|
||
return new Blob([int8Array], { type: 'image/jpeg' }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* Convert a raw number of Bytes to a more user-friendly size in `B` / `kB` / `MB` / `GB` units. | ||
*/ | ||
export function formatBytes(value: unknown, decimals = 2): string { | ||
const bytes = Number(value); | ||
|
||
if (isNaN(bytes)) { | ||
return '0 B'; | ||
} | ||
|
||
const k = 1024; | ||
const dm = decimals < 0 ? 0 : decimals; | ||
const sizes = ['B', 'kB', 'MB', 'GB']; | ||
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k)); | ||
|
||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* Parse a local CSV file and return an array of string arrays, where the inner arrays represent | ||
* the rows in the original CSV file. | ||
* | ||
* Return `null` if for whatever reason the CSV cannot be parsed. | ||
*/ | ||
export async function parseCsv( | ||
filePath?: string, | ||
skipFirstRow = true, | ||
): Promise<Array<string[]> | null> { | ||
if (!filePath || !filePath.endsWith('.csv')) { | ||
return null; | ||
} | ||
|
||
const response = await fetch(filePath); | ||
if (!response) { | ||
return null; | ||
} | ||
|
||
const blob = await response.blob(); | ||
if (!blob) { | ||
return null; | ||
} | ||
|
||
const arrayBuffer = await blob.text(); | ||
if (!arrayBuffer) { | ||
return null; | ||
} | ||
|
||
let rowsOfData: Array<string[]> = [[]]; | ||
rowsOfData = arrayBuffer.split('\n')?.map(row => row.split(',')); | ||
|
||
return skipFirstRow && rowsOfData.length > 0 ? rowsOfData.slice(1) : rowsOfData; | ||
} |
Oops, something went wrong.