From 22ecae5887210e3d3a3d28a2a4ba14a2de75e941 Mon Sep 17 00:00:00 2001 From: Eric Schultz Date: Mon, 1 Oct 2018 15:31:18 -0500 Subject: [PATCH] Add new lib functions --- javascripts/src/lib/date.ts | 63 ++++++++++++++++++++++++ javascripts/src/lib/dedication.ts | 22 +++++++++ javascripts/src/lib/deprecated_format.ts | 15 ++++++ javascripts/src/lib/format.spec.ts | 22 +++++++++ javascripts/src/lib/format.ts | 57 +++++++++++++++++++++ javascripts/src/lib/utils.ts | 4 ++ 6 files changed, 183 insertions(+) create mode 100644 javascripts/src/lib/date.ts create mode 100644 javascripts/src/lib/dedication.ts create mode 100644 javascripts/src/lib/deprecated_format.ts create mode 100644 javascripts/src/lib/format.spec.ts create mode 100644 javascripts/src/lib/format.ts create mode 100644 javascripts/src/lib/utils.ts diff --git a/javascripts/src/lib/date.ts b/javascripts/src/lib/date.ts new file mode 100644 index 00000000..86ecdb7d --- /dev/null +++ b/javascripts/src/lib/date.ts @@ -0,0 +1,63 @@ +// License: LGPL-3.0-or-later +import * as moment from 'moment'; +import 'moment-timezone' + +function momentTz(date:string, timezone:string='UTC'):moment.Moment { + return moment.tz(date, "YYYY-MM-DD HH:mm:ss", 'UTC').tz(timezone) +} + +// Return a date in the format MM/DD/YY for a given date string or moment obj +export function readable_date(date?:string, timezone:string='UTC'):string { + if(!date) return + return momentTz(date,timezone).format("MM/DD/YYYY") +} + +// Given a created_at string (eg. Charge.last.created_at.to_s), convert it to a readable date-time string +export function readable_date_time(date?:string, timezone:string='UTC'):string { + if(!date) return + return momentTz(date,timezone).format("MM/DD/YYYY H:mma z") +} + + +// converts the return value of readable_date_time to it's ISO equivalent +export function readable_date_time_to_iso(date?:string, timezone:string='UTC') { + if(!date) return + return moment.tz(date, 'MM/DD/YYYY H:mma z', timezone) + .tz('UTC') + .toISOString() +} + +// Get the month number (eg 01,02...) for the given date string (or moment obj) +export function get_month(date:string|moment.Moment) { + var monthNum = moment(date).month() + return moment().month(monthNum).format('MMM') +} + +// Get the year (eg 2017) for the given date string (or moment obj) +export function get_year(date:string|moment.Moment) { + return moment(date).year() +} + +// Get the day (number in the month) for the given date string (or moment obj) +export function get_day(date:string|moment.Moment) { + return moment(date).date() +} + + +export class NonprofitTimezonedDates { + constructor(readonly nonprofitTimezone:string){ + + } + + readable_date(date?:string):string{ + return readable_date(date, this.nonprofitTimezone || 'UTC') + } + + readable_date_time(date?:string):string { + return readable_date_time(date, this.nonprofitTimezone || 'UTC') + } + + readable_date_time_to_iso(date?:string):string { + return readable_date_time_to_iso(date, this.nonprofitTimezone || 'UTC') + } +} \ No newline at end of file diff --git a/javascripts/src/lib/dedication.ts b/javascripts/src/lib/dedication.ts new file mode 100644 index 00000000..1ebe9a95 --- /dev/null +++ b/javascripts/src/lib/dedication.ts @@ -0,0 +1,22 @@ +// License: LGPL-3.0-or-later +export interface Dedication { + type?:'honor'|'memory', + supporter_id?: number, + name?:string + contact?: string, + note?:string +} + +export function parseDedication(dedication?:string) : Dedication { + if (!dedication || dedication == "") + return {} + return JSON.parse(dedication) +} + +export function serializeDedication(dedication:Dedication) : string { + return JSON.stringify(dedication) +} + + + + diff --git a/javascripts/src/lib/deprecated_format.ts b/javascripts/src/lib/deprecated_format.ts new file mode 100644 index 00000000..25abd63e --- /dev/null +++ b/javascripts/src/lib/deprecated_format.ts @@ -0,0 +1,15 @@ +// License: LGPL-3.0-or-later + +export function pluralize(quantity:number, plural_word:string) : string{ + var str = String(quantity) + ' ' + if(quantity !== 1) return str+plural_word + else return str + to_singular(plural_word) +} + + +export function to_singular(plural_word:string) : string { + return plural_word + .replace(/ies$/, 'y') + .replace(/oes$/, 'o') + .replace(/s$/, '') +} \ No newline at end of file diff --git a/javascripts/src/lib/format.spec.ts b/javascripts/src/lib/format.spec.ts new file mode 100644 index 00000000..954bc7c6 --- /dev/null +++ b/javascripts/src/lib/format.spec.ts @@ -0,0 +1,22 @@ +// License: LGPL-3.0-or-later +import * as Format from './format' +import 'jest'; + + +describe('Format.dollarsToCents', () => { + + const expectedAmount = 120 + + test("accepts negative amounts",() => + expect(Format.dollarsToCents("-1.20")).toBe(expectedAmount* -1) + ) + + test("strips commas and dollar signs",() => + expect(Format.dollarsToCents("$1,20")).toBe(expectedAmount* 100) + ) + + test("properly handles slightly shorter than normal decimals",() => + expect(Format.dollarsToCents("$1.2")).toBe(expectedAmount) + ) + +}) \ No newline at end of file diff --git a/javascripts/src/lib/format.ts b/javascripts/src/lib/format.ts new file mode 100644 index 00000000..6f872f06 --- /dev/null +++ b/javascripts/src/lib/format.ts @@ -0,0 +1,57 @@ +// License: LGPL-3.0-or-later + +import * as deprecated_format from './deprecated_format' + +export function centsToDollars(cents:string|number|undefined, options:{noCents?:boolean}={}):string { + if(cents === undefined) return '0' + let centsAsNumber:number = undefined + if (typeof cents === 'string') + { + centsAsNumber = Number(cents) + } + else { + centsAsNumber = cents + } + return numberWithCommas((centsAsNumber / 100.0).toFixed(options.noCents ? 0 : 2).toString()).replace(/\.00$/,'') +} + +export function dollarsToCents(dollars:string) { + //strips + dollars = dollars.toString().replace(/[$,]/g, '') + if(dollars.match(/^-?\d+\.\d$/)) { + // could we use toFixed instead? Probably but this is straightforward. + dollars = dollars + "0" + } + if(!dollars.match(/^-?\d+(\.\d\d)?$/)) throw "Invalid dollar amount: " + dollars + return Math.round(Number(dollars) * 100) +} + +export function numberWithCommas(n:string|number):string { + return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",") +} + +export function camelToWords(str:string, os?:any) { + if(!str) return str + return str.replace(/([A-Z])/g, " $1") +} + +export function readableKind(kind:string) { + if (kind === "Donation") return "One-Time Donation" + else if (kind === "OffsitePayment") return "Offsite Donation" + else if (kind === "Ticket") return "Ticket Purchase" + else return camelToWords(kind) +} + + + +export function readableInterval(interval:number, time_unit:string) { + if(interval === 1) return time_unit + 'ly' + if(interval === 4 && time_unit === 'year') return 'quarterly' + if(interval === 2 && time_unit === 'year') return 'biannually' + if(interval === 2 && time_unit === 'week') return 'biweekly' + if(interval === 2 && time_unit === 'month') return 'bimonthly' + else return 'every ' + deprecated_format.pluralize(Number(interval), time_unit + 's') +} + + + diff --git a/javascripts/src/lib/utils.ts b/javascripts/src/lib/utils.ts new file mode 100644 index 00000000..6b0001b4 --- /dev/null +++ b/javascripts/src/lib/utils.ts @@ -0,0 +1,4 @@ +// License: LGPL-3.0-or-later +export function castToNullIfUndef(i:T): T | null{ + return i === undefined ? null : i +} \ No newline at end of file