Merge branch 'master' into alarm-module

This commit is contained in:
Brandon Presley 2022-10-28 16:49:39 +13:00
commit 8504f8b811
16 changed files with 472 additions and 545 deletions

View File

@ -28,6 +28,7 @@ export default function EditSet() {
milliseconds, milliseconds,
!!settings.vibrate, !!settings.vibrate,
settings.sound, settings.sound,
!!settings.noSound,
); );
const nextAlarm = new Date(); const nextAlarm = new Date();
nextAlarm.setTime(nextAlarm.getTime() + milliseconds); nextAlarm.setTime(nextAlarm.getTime() + milliseconds);

View File

@ -5,6 +5,7 @@ import {Divider, List, Menu, Text} from 'react-native-paper';
import {HomePageParams} from './home-page-params'; import {HomePageParams} from './home-page-params';
import Set from './set'; import Set from './set';
import {deleteSet} from './set.service'; import {deleteSet} from './set.service';
import {format} from './time';
import useDark from './use-dark'; import useDark from './use-dark';
import {useSettings} from './use-settings'; import {useSettings} from './use-settings';
@ -63,7 +64,7 @@ export default function SetItem({
alignSelf: 'center', alignSelf: 'center',
color: dark ? '#909090ff' : '#717171ff', color: dark ? '#909090ff' : '#717171ff',
}}> }}>
{item.created?.replace('T', ' ')} {format(item.created || '', settings.date)}
</Text> </Text>
)} )}
<Menu <Menu

View File

@ -33,6 +33,7 @@ export default function SettingsPage() {
showSets, showSets,
theme, theme,
alarm, alarm,
noSound,
} = settings; } = settings;
const {color, setColor} = useColor(); const {color, setColor} = useColor();
const {toast} = useSnackbar(); const {toast} = useSnackbar();
@ -139,9 +140,19 @@ export default function SettingsPage() {
[toast, update], [toast, update],
); );
const changeNoSound = useCallback(
(enabled: boolean) => {
update(enabled, 'noSound');
if (enabled) toast('Disable sound on rest timer alarms.', 4000);
else toast('Enabled sound for rest timer alarms.', 4000);
},
[toast, update],
);
const switches: Input<boolean>[] = [ const switches: Input<boolean>[] = [
{name: 'Rest timers', value: !!alarm, onChange: changeAlarmEnabled}, {name: 'Rest timers', value: !!alarm, onChange: changeAlarmEnabled},
{name: 'Vibrate', value: !!vibrate, onChange: changeVibrate}, {name: 'Vibrate', value: !!vibrate, onChange: changeVibrate},
{name: 'Disable sound', value: !!noSound, onChange: changeNoSound},
{name: 'Record notifications', value: !!notify, onChange: changeNotify}, {name: 'Record notifications', value: !!notify, onChange: changeNotify},
{name: 'Show images', value: !!images, onChange: changeImages}, {name: 'Show images', value: !!images, onChange: changeImages},
{name: 'Show unit', value: !!showUnit, onChange: changeUnit}, {name: 'Show unit', value: !!showUnit, onChange: changeUnit},
@ -217,16 +228,18 @@ export default function SettingsPage() {
dropdownIconColor={color} dropdownIconColor={color}
selectedValue={settings.date} selectedValue={settings.date}
onValueChange={changeDate}> onValueChange={changeDate}>
<Picker.Item value="%Y-%m-%d %H:%M" label="1990-12-24 15:05" />
<Picker.Item value="%Y-%m-%d" label="1990-12-24" />
<Picker.Item value="%d/%m" label="24/12 (dd/MM)" />
<Picker.Item value="%H:%M" label="15:05 (24-hour time)" />
<Picker.Item value="%h:%M %p" label="3:05 PM (12-hour time)" />
<Picker.Item value="%d/%m/%y" label="24/12/1996" />
<Picker.Item value="%A %h:%M %p" label="Monday 3:05 PM" />
<Picker.Item <Picker.Item
value="%Y-%m-%d %H:%M" value="%d/%m/%y %h:%M %p"
label="Format date as 1990-12-24 15:05" label="24/12/1990 3:05 PM"
/> />
<Picker.Item <Picker.Item value="%d/%m %h:%M %p" label="24/12 3:05 PM" />
value="%Y-%m-%d"
label="Format date as 1990-12-24 (YYYY-MM-dd)"
/>
<Picker.Item value="%d/%m" label="Format date as 24/12 (dd/MM)" />
<Picker.Item value="%H:%M" label="Format date as 15:05 (HH:MM)" />
</Picker> </Picker>
)} )}
{'alarm sound'.includes(search.toLowerCase()) && ( {'alarm sound'.includes(search.toLowerCase()) && (

View File

@ -11,7 +11,7 @@ import MassiveInput from './MassiveInput';
import {useSnackbar} from './MassiveSnack'; import {useSnackbar} from './MassiveSnack';
import {PlanPageParams} from './plan-page-params'; import {PlanPageParams} from './plan-page-params';
import Set from './set'; import Set from './set';
import {addSet, countManyToday, getDistinctSets} from './set.service'; import {addSet, countMany} from './set.service';
import SetForm from './SetForm'; import SetForm from './SetForm';
import StackHeader from './StackHeader'; import StackHeader from './StackHeader';
import {useSettings} from './use-settings'; import {useSettings} from './use-settings';
@ -30,7 +30,6 @@ export default function StartPlan() {
const [selected, setSelected] = useState(0); const [selected, setSelected] = useState(0);
const {settings} = useSettings(); const {settings} = useSettings();
const [counts, setCounts] = useState<CountMany[]>(); const [counts, setCounts] = useState<CountMany[]>();
const [distinctSets, setDistinctSets] = useState<Set[]>();
const weightRef = useRef<TextInput>(null); const weightRef = useRef<TextInput>(null);
const repsRef = useRef<TextInput>(null); const repsRef = useRef<TextInput>(null);
const unitRef = useRef<TextInput>(null); const unitRef = useRef<TextInput>(null);
@ -44,16 +43,10 @@ export default function StartPlan() {
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
countManyToday().then(newCounts => { countMany(workouts).then(newCounts => {
setCounts(newCounts); setCounts(newCounts);
console.log(`${StartPlan.name}.focus:`, {newCounts}); console.log(`${StartPlan.name}.focus:`, {newCounts});
}); });
getDistinctSets({limit: 100, offset: 0, search: '%'}).then(
newDistinct => {
setDistinctSets(newDistinct);
console.log(`${StartPlan.name}.focus:`, {newDistinct});
},
);
}, [params]), }, [params]),
); );
@ -69,7 +62,7 @@ export default function StartPlan() {
image: set.image, image: set.image,
unit, unit,
}); });
countManyToday().then(setCounts); countMany(workouts).then(setCounts);
if ( if (
settings.notify && settings.notify &&
(+weight > best.weight || (+reps > best.reps && +weight === best.weight)) (+weight > best.weight || (+reps > best.reps && +weight === best.weight))
@ -95,10 +88,11 @@ export default function StartPlan() {
const select = useCallback( const select = useCallback(
async (index: number) => { async (index: number) => {
setSelected(index); setSelected(index);
console.log(`${StartPlan.name}.next:`, {name, workouts}); console.log(`${StartPlan.name}.next:`, {name});
const workout = workouts[index]; if (!counts) return;
const workout = counts[index];
console.log(`${StartPlan.name}.next:`, {workout}); console.log(`${StartPlan.name}.next:`, {workout});
const newBest = await getBestSet(workout); const newBest = await getBestSet(workout.name);
setMinutes(newBest.minutes); setMinutes(newBest.minutes);
setSeconds(newBest.seconds); setSeconds(newBest.seconds);
setName(newBest.name); setName(newBest.name);
@ -110,20 +104,6 @@ export default function StartPlan() {
[name, workouts], [name, workouts],
); );
const getDescription = useCallback(
(countName: string) => {
const count = counts?.find(c => c.name === countName);
console.log(`${StartPlan.name}:`, {count, countName});
if (!distinctSets) return;
const distinct = distinctSets.find(d => d.name === countName);
console.log(`${StartPlan.name}:`, {distinct});
if (settings.showSets)
return `${count?.total || 0} / ${distinct?.sets || 3}`;
return count?.total || '0';
},
[counts, distinctSets, settings.showSets],
);
return ( return (
<> <>
<StackHeader title={params.plan.days.replace(/,/g, ', ')} /> <StackHeader title={params.plan.days.replace(/,/g, ', ')} />
@ -157,13 +137,17 @@ export default function StartPlan() {
innerRef={unitRef} innerRef={unitRef}
/> />
)} )}
{counts && distinctSets && ( {counts && (
<FlatList <FlatList
data={workouts} data={counts}
renderItem={({item, index}) => ( renderItem={({item, index}) => (
<List.Item <List.Item
title={item} title={item.name}
description={getDescription(item)} description={
settings.showSets
? `${item.total} / ${item.sets ?? 3}`
: item.total.toString()
}
onPress={() => select(index)} onPress={() => select(index)}
left={() => ( left={() => (
<View <View

View File

@ -64,7 +64,7 @@ export default function ViewBest() {
yData={volumes.map(v => v.value)} yData={volumes.map(v => v.value)}
yFormat={(value: number) => yFormat={(value: number) =>
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${ `${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
volumes[0].unit volumes[0].unit || 'kg'
}` }`
} }
xData={weights} xData={weights}

View File

@ -43,8 +43,8 @@ android {
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 36069 versionCode 36071
versionName "1.43" versionName "1.45"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) { if (isNewArchitectureEnabled()) {

View File

@ -67,7 +67,7 @@ class AlarmModule internal constructor(context: ReactApplicationContext?) :
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
@ReactMethod @ReactMethod
fun timer(milliseconds: Int, vibrate: Boolean, sound: String?) { fun timer(milliseconds: Int, vibrate: Boolean, sound: String?, noSound: Boolean = false) {
Log.d("AlarmModule", "Queue alarm for $milliseconds delay") Log.d("AlarmModule", "Queue alarm for $milliseconds delay")
val intent = Intent(reactApplicationContext, AlarmModule::class.java) val intent = Intent(reactApplicationContext, AlarmModule::class.java)
currentActivity?.startActivityForResult(intent, 0) currentActivity?.startActivityForResult(intent, 0)

View File

@ -21,11 +21,13 @@ class AlarmService : Service(), OnPreparedListener {
return START_STICKY return START_STICKY
} }
val sound = intent.extras?.getString("sound") val sound = intent.extras?.getString("sound")
if (sound == null) { val noSound = intent.extras?.getBoolean("noSound") == true
if (sound == null && !noSound) {
mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon) mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon)
mediaPlayer?.start() mediaPlayer?.start()
mediaPlayer?.setOnCompletionListener { vibrator?.cancel() } mediaPlayer?.setOnCompletionListener { vibrator?.cancel() }
} else { } else if (sound != null && !noSound) {
mediaPlayer = MediaPlayer().apply { mediaPlayer = MediaPlayer().apply {
setAudioAttributes( setAudioAttributes(
AudioAttributes.Builder() AudioAttributes.Builder()
@ -39,6 +41,7 @@ class AlarmService : Service(), OnPreparedListener {
setOnCompletionListener { vibrator?.cancel() } setOnCompletionListener { vibrator?.cancel() }
} }
} }
val pattern = longArrayOf(0, 300, 1300, 300, 1300, 300) val pattern = longArrayOf(0, 300, 1300, 300, 1300, 300)
vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = val vibratorManager =

View File

@ -20,11 +20,13 @@ class TimerService : Service() {
private var endMs: Int = 0 private var endMs: Int = 0
private var currentMs: Long = 0 private var currentMs: Long = 0
private var vibrate: Boolean = true private var vibrate: Boolean = true
private var noSound: Boolean = false
private var sound: String? = null private var sound: String? = null
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
vibrate = intent?.extras?.getBoolean("vibrate") == true vibrate = intent?.extras?.getBoolean("vibrate") == true
noSound = intent?.extras?.getBoolean("noSound") == true
sound = intent?.extras?.getString("sound") sound = intent?.extras?.getString("sound")
val manager = getManager() val manager = getManager()
manager.cancel(NOTIFICATION_ID_DONE) manager.cancel(NOTIFICATION_ID_DONE)
@ -93,9 +95,11 @@ class TimerService : Service() {
val manager = getManager() val manager = getManager()
manager.notify(NOTIFICATION_ID_DONE, builder.build()) manager.notify(NOTIFICATION_ID_DONE, builder.build())
manager.cancel(NOTIFICATION_ID_PENDING) manager.cancel(NOTIFICATION_ID_PENDING)
val alarmIntent = Intent(applicationContext, AlarmService::class.java) val alarmIntent = Intent(applicationContext, AlarmService::class.java).apply {
alarmIntent.putExtra("vibrate", vibrate) putExtra("vibrate", vibrate)
alarmIntent.putExtra("sound", sound) putExtra("sound", sound)
putExtra("noSound", noSound)
}
applicationContext.startService(alarmIntent) applicationContext.startService(alarmIntent)
} }
} }
@ -124,11 +128,13 @@ class TimerService : Service() {
val stopIntent = Intent(context, StopTimer::class.java) val stopIntent = Intent(context, StopTimer::class.java)
val pendingStop = val pendingStop =
PendingIntent.getService(context, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE) PendingIntent.getService(context, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE)
val addIntent = Intent(context, TimerService::class.java) val addIntent = Intent(context, TimerService::class.java).apply {
addIntent.action = "add" action = "add"
addIntent.putExtra("vibrate", vibrate) putExtra("vibrate", vibrate)
addIntent.putExtra("sound", sound) putExtra("sound", sound)
addIntent.data = Uri.parse("$currentMs") putExtra("noSound", noSound)
data = Uri.parse("$currentMs")
}
val pendingAdd = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val pendingAdd = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getService(context, 0, addIntent, PendingIntent.FLAG_MUTABLE) PendingIntent.getService(context, 0, addIntent, PendingIntent.FLAG_MUTABLE)
} else { } else {

View File

@ -1,4 +1,5 @@
export default interface CountMany { export default interface CountMany {
name: string; name: string;
total: number; total: number;
sets?: number;
} }

22
db.ts
View File

@ -41,16 +41,16 @@ const migrations = [
) )
`, `,
` `
ALTER TABLE sets ADD COLUMN hidden DEFAULT 0 ALTER TABLE sets ADD COLUMN hidden DEFAULT false
`, `,
` `
ALTER TABLE settings ADD COLUMN notify DEFAULT 0 ALTER TABLE settings ADD COLUMN notify DEFAULT false
`, `,
` `
ALTER TABLE sets ADD COLUMN image TEXT NULL ALTER TABLE sets ADD COLUMN image TEXT NULL
`, `,
` `
ALTER TABLE settings ADD COLUMN images BOOLEAN DEFAULT 1 ALTER TABLE settings ADD COLUMN images BOOLEAN DEFAULT true
`, `,
` `
SELECT * FROM settings LIMIT 1 SELECT * FROM settings LIMIT 1
@ -74,7 +74,7 @@ const migrations = [
ALTER TABLE sets ADD COLUMN seconds INTEGER NOT NULL DEFAULT 30 ALTER TABLE sets ADD COLUMN seconds INTEGER NOT NULL DEFAULT 30
`, `,
` `
ALTER TABLE settings ADD COLUMN showUnit BOOLEAN DEFAULT 1 ALTER TABLE settings ADD COLUMN showUnit BOOLEAN DEFAULT true
`, `,
` `
ALTER TABLE sets ADD COLUMN steps TEXT NULL ALTER TABLE sets ADD COLUMN steps TEXT NULL
@ -94,10 +94,10 @@ const migrations = [
UPDATE settings SET showUnit = 1 UPDATE settings SET showUnit = 1
`, `,
` `
ALTER TABLE settings ADD COLUMN workouts BOOLEAN DEFAULT 1 ALTER TABLE settings ADD COLUMN workouts BOOLEAN DEFAULT true
`, `,
` `
ALTER TABLE settings ADD COLUMN steps BOOLEAN DEFAULT 1 ALTER TABLE settings ADD COLUMN steps BOOLEAN DEFAULT true
`, `,
` `
ALTER TABLE settings ADD COLUMN nextAlarm TEXT NULL ALTER TABLE settings ADD COLUMN nextAlarm TEXT NULL
@ -109,13 +109,19 @@ const migrations = [
ALTER TABLE settings ADD COLUMN date TEXT NULL ALTER TABLE settings ADD COLUMN date TEXT NULL
`, `,
` `
ALTER TABLE settings ADD COLUMN showDate BOOLEAN DEFAULT 0 ALTER TABLE settings ADD COLUMN showDate BOOLEAN DEFAULT false
`, `,
` `
ALTER TABLE settings ADD COLUMN theme TEXT ALTER TABLE settings ADD COLUMN theme TEXT
`, `,
` `
ALTER TABLE settings ADD COLUMN showSets BOOLEAN DEFAULT 1 ALTER TABLE settings ADD COLUMN showSets BOOLEAN DEFAULT true
`,
`
CREATE INDEX sets_created ON sets(created)
`,
`
ALTER TABLE settings ADD COLUMN noSound BOOLEAN DEFAULT false
`, `,
` `
CREATE INDEX sets_created ON sets(created) CREATE INDEX sets_created ON sets(created)

View File

@ -1,6 +1,6 @@
{ {
"name": "massive", "name": "massive",
"version": "1.43", "version": "1.45",
"private": true, "private": true,
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {
@ -23,19 +23,19 @@
"@types/react-native-vector-icons": "^6.4.12", "@types/react-native-vector-icons": "^6.4.12",
"babel-plugin-transform-remove-console": "^6.9.4", "babel-plugin-transform-remove-console": "^6.9.4",
"react": "^18.2.0", "react": "^18.2.0",
"react-native": "^0.70.1", "react-native": "^0.70.4",
"react-native-document-picker": "^8.1.1", "react-native-document-picker": "^8.1.2",
"react-native-file-access": "^2.5.0", "react-native-file-access": "^2.5.0",
"react-native-gesture-handler": "^2.6.1", "react-native-gesture-handler": "^2.8.0",
"react-native-linear-gradient": "^2.6.2", "react-native-linear-gradient": "^2.6.2",
"react-native-pager-view": "^6.0.0", "react-native-pager-view": "^6.0.1",
"react-native-paper": "^4.12.4", "react-native-paper": "^4.12.5",
"react-native-reanimated": "^2.10.0", "react-native-reanimated": "^2.12.0",
"react-native-safe-area-context": "^4.3.3", "react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.17.0", "react-native-screens": "^3.18.2",
"react-native-share": "^7.9.0", "react-native-share": "^7.9.1",
"react-native-sqlite-storage": "^6.0.1", "react-native-sqlite-storage": "^6.0.1",
"react-native-svg": "^13.2.0", "react-native-svg": "^13.4.0",
"react-native-svg-charts": "^5.4.0", "react-native-svg-charts": "^5.4.0",
"react-native-vector-icons": "^9.2.0", "react-native-vector-icons": "^9.2.0",
"react-native-view-shot": "^3.4.0" "react-native-view-shot": "^3.4.0"
@ -48,9 +48,9 @@
"@types/react-test-renderer": "^18.0.0", "@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.29.0", "@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0", "@typescript-eslint/parser": "^5.29.0",
"eslint": "^7.32.0", "eslint": "^8.26.0",
"metro-react-native-babel-preset": "^0.70.3", "metro-react-native-babel-preset": "^0.73.3",
"typescript": "^4.4.4" "typescript": "^4.8.4"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app", "extends": "react-app",

View File

@ -82,18 +82,13 @@ export const getSets = async ({
}: PageParams): Promise<Set[]> => { }: PageParams): Promise<Set[]> => {
const select = ` const select = `
SELECT id, name, reps, weight, sets, minutes, seconds, SELECT id, name, reps, weight, sets, minutes, seconds,
STRFTIME(?, created) as created, unit, image, steps created, unit, image, steps
FROM sets FROM sets
WHERE name LIKE ? AND NOT hidden WHERE name LIKE ? AND NOT hidden
ORDER BY STRFTIME('%Y-%m-%d %H:%M', created) DESC ORDER BY STRFTIME('%Y-%m-%d %H:%M', created) DESC
LIMIT ? OFFSET ? LIMIT ? OFFSET ?
`; `;
const [result] = await db.executeSql(select, [ const [result] = await db.executeSql(select, [`%${search}%`, limit, offset]);
format,
`%${search}%`,
limit,
offset,
]);
return result.rows.raw(); return result.rows.raw();
}; };
@ -166,14 +161,21 @@ export const countToday = async (name: string): Promise<number> => {
return Number(result.rows.item(0)?.total); return Number(result.rows.item(0)?.total);
}; };
export const countManyToday = async (): Promise<CountMany[]> => { export const countMany = async (names: string[]): Promise<CountMany[]> => {
const questions = names.map(_ => '?').join(',');
console.log({questions, names});
const select = ` const select = `
SELECT COUNT(*) as total, name FROM sets SELECT workouts.name, COUNT(sets.id) as total, workouts.sets
WHERE created LIKE strftime('%Y-%m-%d%%', 'now', 'localtime') FROM (
AND NOT hidden SELECT distinct name, sets FROM sets
GROUP BY name WHERE name IN (${questions})
) workouts
LEFT JOIN sets ON sets.name = workouts.name
AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime')
AND NOT sets.hidden
GROUP BY workouts.name;
`; `;
const [result] = await db.executeSql(select); const [result] = await db.executeSql(select, names);
return result.rows.raw(); return result.rows.raw();
}; };

View File

@ -11,5 +11,5 @@ export default interface Settings {
showDate: number; showDate: number;
theme: 'system' | 'dark' | 'light'; theme: 'system' | 'dark' | 'light';
showSets: number; showSets: number;
nextAlarm?: string; noSound: number;
} }

45
time.ts
View File

@ -14,3 +14,48 @@ export function formatMonth(iso: string) {
const mm = (date.getMonth() + 1).toString(); const mm = (date.getMonth() + 1).toString();
return `${dd}/${mm}`; return `${dd}/${mm}`;
} }
function twelveHour(twentyFourHour: string) {
const [hourString, minute] = twentyFourHour.split(':');
const hour = +hourString % 24;
return (hour % 12 || 12) + ':' + minute + (hour < 12 ? ' AM' : ' PM');
}
function dayOfWeek(iso: string) {
const date = new Date(iso);
const day = date.getDay();
const target = DAYS[day === 0 ? 0 : day - 1];
return target.slice(0, 3);
}
/**
* @param iso ISO formatted date, e.g. 1996-12-24T14:03:04
* @param kind Intended format for the date, e.g. '%Y-%m-%d %H:%M'
*/
export function format(iso: string, kind: string) {
const split = iso.split('T');
const [year, month, day] = split[0].split('-');
const time = twelveHour(split[1]);
switch (kind) {
case '%Y-%m-%d %H:%M':
return iso.replace('T', ' ').replace(/:\d{2}/, '');
case '%Y-%m-%d':
return split[0];
case '%H:%M':
return split[1].replace(/:\d{2}/, '');
case '%d/%m/%y %h:%M %p':
return `${day}/${month}/${year} ${time}`;
case '%d/%m %h:%M %p':
return `${day}/${month} ${time}`;
case '%d/%m/%y':
return `${day}/${month}/${year}`;
case '%d/%m':
return `${day}/${month}`;
case '%h:%M %p':
return time;
case '%A %h:%M %p':
return dayOfWeek(iso) + ' ' + time;
default:
return iso;
}
}

775
yarn.lock

File diff suppressed because it is too large Load Diff