refactor(popup): match styles/reduce paint flicker (#136)

* refactor: match popup styles/reduce paint flicker

* fix: useSchedules hook

* feat: popup 

* fix: repaint issue on popup body

* fix: initial active schedule

* fix: center justification

* fix: reactivity error
This commit is contained in:
Razboy20
2024-03-13 12:33:54 -05:00
committed by GitHub
parent 0dff12232c
commit 1d8da6579e
8 changed files with 149 additions and 179 deletions

View File

@@ -2,52 +2,61 @@ import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
import { UserSchedule } from '@shared/types/UserSchedule';
import { useEffect, useState } from 'react';
let schedulesCache = [];
let activeIndexCache = 0;
let initialLoad = true;
/**
* Fetches the user schedules from storage and sets the cached state.
*/
async function fetchData() {
const [storedSchedules, storedActiveIndex] = await Promise.all([
UserScheduleStore.get('schedules'),
UserScheduleStore.get('activeIndex'),
]);
schedulesCache = storedSchedules.map(s => new UserSchedule(s));
activeIndexCache = storedActiveIndex;
}
/**
* Custom hook that manages user schedules.
* @returns A tuple containing the active schedule and an array of all schedules.
*/
export default function useSchedules(): [active: UserSchedule | null, schedules: UserSchedule[]] {
const [schedules, setSchedules] = useState<UserSchedule[]>([]);
const [activeSchedule, setActiveSchedule] = useState<UserSchedule | null>(null);
const [schedules, setSchedules] = useState<UserSchedule[]>(schedulesCache);
const [activeIndex, setActiveIndex] = useState<number>(activeIndexCache);
const [activeSchedule, setActiveSchedule] = useState<UserSchedule | null>(schedules[activeIndex]);
if (initialLoad) {
initialLoad = false;
// trigger suspense
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw new Promise(res => {
fetchData().then(res);
});
}
useEffect(() => {
const fetchData = async () => {
const [storedSchedules, storedActiveIndex] = await Promise.all([
UserScheduleStore.get('schedules'),
UserScheduleStore.get('activeIndex'),
]);
setSchedules(storedSchedules.map(s => new UserSchedule(s)));
setActiveSchedule(new UserSchedule(storedSchedules[storedActiveIndex]));
const l1 = UserScheduleStore.listen('schedules', ({ newValue }) => {
setSchedules(newValue.map(s => new UserSchedule(s)));
});
const l2 = UserScheduleStore.listen('activeIndex', ({ newValue }) => {
setActiveIndex(newValue);
});
return () => {
UserScheduleStore.removeListener(l1);
UserScheduleStore.removeListener(l2);
};
fetchData();
const setupListeners = () => {
const l1 = UserScheduleStore.listen('schedules', ({ newValue }) => {
setSchedules(newValue.map(s => new UserSchedule(s)));
setActiveSchedule(currentActive => {
const newActiveIndex = newValue.findIndex(s => s.name === currentActive?.name);
return new UserSchedule(newValue[newActiveIndex]);
});
});
const l2 = UserScheduleStore.listen('activeIndex', ({ newValue }) => {
setSchedules(currentSchedules => {
setActiveSchedule(new UserSchedule(currentSchedules[newValue]));
return currentSchedules;
});
});
return () => {
UserScheduleStore.removeListener(l1);
UserScheduleStore.removeListener(l2);
};
};
const init = UserScheduleStore.initialize();
init.then(() => setupListeners()).catch(console.error);
}, []);
// recompute active schedule on a schedule/index change
useEffect(() => {
setActiveSchedule(schedules[activeIndex]);
});
return [activeSchedule, schedules];
}
@@ -57,6 +66,7 @@ export default function useSchedules(): [active: UserSchedule | null, schedules:
* @returns A promise that resolves when the active schedule has been switched.
*/
export async function switchSchedule(name: string): Promise<void> {
console.log('Switching schedule...');
const schedules = await UserScheduleStore.get('schedules');
const activeIndex = schedules.findIndex(s => s.name === name);
await UserScheduleStore.set('activeIndex', activeIndex);