From e3da3e26d12aed7771841ae1a2ab10594d38554a Mon Sep 17 00:00:00 2001 From: Naomi Calabretta Date: Mon, 13 Jan 2025 16:29:51 +0100 Subject: [PATCH] some more reminders work --- src/components/PopupPicker.vue | 60 ++++++++++ src/lib/db/entities.d.ts | 59 +++++---- src/lib/db/impl/dexie/reminders.ts | 39 +++++- src/lib/db/impl/dexie/types.d.ts | 1 + src/lib/db/impl/tauri/reminders.ts | 37 +++++- src/lib/db/tables/reminders.ts | 14 ++- src/modals/ReminderEdit.vue | 186 +++++++++++++++++++++-------- src/views/options/Reminders.vue | 79 ++++++++++-- translations/en/options.json | 11 +- translations/en/other.json | 35 ++++++ 10 files changed, 435 insertions(+), 86 deletions(-) create mode 100644 src/components/PopupPicker.vue diff --git a/src/components/PopupPicker.vue b/src/components/PopupPicker.vue new file mode 100644 index 0000000..d9e9537 --- /dev/null +++ b/src/components/PopupPicker.vue @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/src/lib/db/entities.d.ts b/src/lib/db/entities.d.ts index 0d18813..2ebca13 100644 --- a/src/lib/db/entities.d.ts +++ b/src/lib/db/entities.d.ts @@ -1,31 +1,33 @@ -export type UUIDable = { +export interface UUIDable { uuid: UUID }; export type UUID = string; -export type BoardMessage = UUIDable & { +export interface BoardMessage extends UUIDable { member: UUID, title: string, body: string, date: Date } -export type BoardMessageComplete = Omit & { member: Member } +export interface BoardMessageComplete extends BoardMessage { + member: Member +} -export type ChatMessage = UUIDable & { +export interface ChatMessage extends UUIDable { chat: UUID, member: UUID, date: Date, message: string, } -export type Chat = UUIDable & { +export interface Chat extends UUIDable { name: string, image?: File } -export type FrontingEntry = UUIDable & { +export interface FrontingEntry extends UUIDable { member: UUID, startTime: Date, endTime?: Date, @@ -33,9 +35,11 @@ export type FrontingEntry = UUIDable & { customStatus?: string } -export type FrontingEntryComplete = Omit & { member: Member } +export interface FrontingEntryComplete extends FrontingEntry { + member: Member +} -export type JournalPost = UUIDable & { +export interface JournalPost extends UUIDable { member: UUID, date: Date, title: string, @@ -45,12 +49,12 @@ export type JournalPost = UUIDable & { tags: UUID[] // array of UUIDs } -export type Attachment = UUIDable & { +export interface Attachment extends UUIDable { name: string, file: File } -export type Member = UUIDable & { +export interface Member extends UUIDable { name: string, pronouns?: string, description?: string, @@ -62,32 +66,47 @@ export type Member = UUIDable & { tags: UUID[] // array of UUIDs } -type ReminderBase = UUIDable & { +interface ReminderBase extends UUIDable { name: string, title: string, message: string, - nativeId?: number + nativeId?: number // if nativeId is present then the reminder is active } -export type EventReminder = ReminderBase & { +interface EventReminder extends ReminderBase { type: "event", triggeringEvent: { type: "memberAdded" | "memberRemoved", filterQuery?: string }, - delay: number // seconds + delay: { + hours: number, + minutes: number + }, // make it either-or in regards to PeriodicReminder - scheduleOn?: never + scheduleEveryInterval?: never, + scheduleEveryWeekday?: never, + scheduleTimeAt?: never } -export type PeriodicReminder = ReminderBase & { +interface PeriodicReminder extends ReminderBase { type: "periodic", - scheduleOn: { + scheduleEveryInterval?: { year?: number, month?: number, day?: number, - weekday?: 1 | 2 | 3 | 4 | 5 | 6 | 7, + }, + scheduleEveryWeekday?: { + monday?: boolean, + tuesday?: boolean, + wednesday?: boolean, + thursday?: boolean, + friday?: boolean, + saturday?: boolean, + sunday?: boolean + }, + scheduleTimeAt?: { hour?: number, minute?: number, second?: number @@ -100,13 +119,13 @@ export type PeriodicReminder = ReminderBase & { export type Reminder = EventReminder | PeriodicReminder; -export type System = UUIDable & { +export interface System extends UUIDable { name: string, description?: string, image?: File } -export type Tag = UUIDable & { +export interface Tag extends UUIDable { name: string, description?: string, type: "member" | "journal", diff --git a/src/lib/db/impl/dexie/reminders.ts b/src/lib/db/impl/dexie/reminders.ts index cb03d79..d5fb1a6 100644 --- a/src/lib/db/impl/dexie/reminders.ts +++ b/src/lib/db/impl/dexie/reminders.ts @@ -1,20 +1,24 @@ import { db } from "."; import { DatabaseEvents, DatabaseEvent } from "../../events"; import { makeUUIDv5 } from "../../../util/uuid"; -import { UUIDable, Reminder } from "../../entities"; +import { UUIDable, Reminder, UUID } from "../../entities"; import { getSystemUUID } from "./system"; async function genid(name: string) { return makeUUIDv5((await getSystemUUID())!, `reminders\0${name}\0${Date.now()}`); } +export function getReminders(){ + return db.reminders.toArray(); +} + export async function newReminder(reminder: Omit) { try{ const uuid = await genid(reminder.name); await db.reminders.add({ ...reminder, uuid - }); + } as Reminder); DatabaseEvents.dispatchEvent(new DatabaseEvent("updated", { table: "reminders", event: "new", @@ -25,3 +29,34 @@ export async function newReminder(reminder: Omit) { return false; } } + +export async function removeReminder(uuid: UUID) { + try { + await db.reminders.delete(uuid); + DatabaseEvents.dispatchEvent(new DatabaseEvent("updated", { + table: "reminders", + event: "deleted", + data: uuid + })); + return true; + } catch (error) { + return false; + } +} + +export async function updateReminder(uuid: UUID, newContent: Partial) { + try{ + const updated = await db.reminders.update(uuid, newContent); + if(updated) { + DatabaseEvents.dispatchEvent(new DatabaseEvent("updated", { + table: "reminders", + event: "modified", + data: uuid + })); + return true; + } + return false; + }catch(error){ + return false; + } +} diff --git a/src/lib/db/impl/dexie/types.d.ts b/src/lib/db/impl/dexie/types.d.ts index 8c3b934..8875ba8 100644 --- a/src/lib/db/impl/dexie/types.d.ts +++ b/src/lib/db/impl/dexie/types.d.ts @@ -1,4 +1,5 @@ import Dexie, { Table } from "dexie"; +import { BoardMessage, Chat, ChatMessage, FrontingEntry, JournalPost, Member, Reminder, System, Tag } from "../../entities"; export type AmpersandDexieDatabase = Dexie & { boardMessages: Table chats: Table diff --git a/src/lib/db/impl/tauri/reminders.ts b/src/lib/db/impl/tauri/reminders.ts index 09f4da0..d67a21e 100644 --- a/src/lib/db/impl/tauri/reminders.ts +++ b/src/lib/db/impl/tauri/reminders.ts @@ -1,13 +1,17 @@ import { db } from "."; import { DatabaseEvents, DatabaseEvent } from "../../events"; import { makeUUIDv5 } from "../../../util/uuid"; -import { UUIDable, Reminder } from "../../entities"; +import { UUIDable, Reminder, UUID } from "../../entities"; import { getSystemUUID } from "./system"; async function genid(name: string) { return makeUUIDv5((await getSystemUUID())!, `reminders\0${name}\0${Date.now()}`); } +export function getReminders(){ + return db.reminders.toArray(); +} + export async function newReminder(reminder: Omit) { try{ const uuid = await genid(reminder.name); @@ -25,3 +29,34 @@ export async function newReminder(reminder: Omit) { return false; } } + +export async function removeReminder(uuid: UUID) { + try { + await db.reminders.delete(uuid); + DatabaseEvents.dispatchEvent(new DatabaseEvent("updated", { + table: "reminders", + event: "deleted", + data: uuid + })); + return true; + } catch (error) { + return false; + } +} + +export async function updateReminder(uuid: UUID, newContent: Partial) { + try{ + const updated = await db.reminders.update(uuid, newContent); + if(updated) { + DatabaseEvents.dispatchEvent(new DatabaseEvent("updated", { + table: "reminders", + event: "modified", + data: uuid + })); + return true; + } + return false; + }catch(error){ + return false; + } +} diff --git a/src/lib/db/tables/reminders.ts b/src/lib/db/tables/reminders.ts index 14823f2..b73d02d 100644 --- a/src/lib/db/tables/reminders.ts +++ b/src/lib/db/tables/reminders.ts @@ -1,7 +1,19 @@ -import { Reminder, UUIDable } from '../entities'; +import { Reminder, UUID, UUIDable } from '../entities'; const impl = await ("isTauri" in window ? import('../impl/tauri/reminders') : import('../impl/dexie/reminders')); +export function getReminders(){ + return impl.getReminders(); +} + export function newReminder(reminder: Omit) { return impl.newReminder(reminder); } + +export function removeReminder(uuid: UUID){ + return impl.removeReminder(uuid); +} + +export function updateReminder(uuid: UUID, newContent: Partial) { + return impl.updateReminder(uuid, newContent); +} diff --git a/src/modals/ReminderEdit.vue b/src/modals/ReminderEdit.vue index 3c295b4..30bac04 100644 --- a/src/modals/ReminderEdit.vue +++ b/src/modals/ReminderEdit.vue @@ -30,10 +30,12 @@ import backMD from "@material-design-icons/svg/outlined/arrow_back.svg"; import MD3SegmentButton from '../components/MD3SegmentButton.vue'; + import PopupPicker from "../components/PopupPicker.vue"; - import { inject, ref } from "vue"; + import { inject, reactive, ref, toRaw, watch } from "vue"; import { PartialBy } from "../lib/types"; - import { EventReminder, Reminder } from "../lib/db/entities"; + import { EventReminder, PeriodicReminder, Reminder } from "../lib/db/entities"; + import { newReminder, updateReminder } from "../lib/db/tables/reminders"; const isIOS = inject("isIOS")!; @@ -44,9 +46,51 @@ const reminder = ref(props.reminder); const self = ref(); + const eventDelayPopupPicker = ref(); + + const eventDelayPickerValue = reactive(new Map()); + + async function save(){ + const uuid = reminder.value?.uuid; + const _reminder = toRaw(reminder.value); + + if(_reminder.type === "event"){ + delete (_reminder as EventReminder).scheduleEveryInterval; + delete (_reminder as EventReminder).scheduleEveryWeekday; + delete (_reminder as EventReminder).scheduleTimeAt; + } else { + delete (_reminder as PeriodicReminder).delay; + delete (_reminder as PeriodicReminder).triggeringEvent; + } + + if(!uuid) { + await newReminder({..._reminder }); + + await modalController.dismiss(null, "added"); + + return; + } + + await updateReminder(uuid, { ..._reminder } as Reminder); + + try{ + await modalController.dismiss(null, "modified"); + }catch(_){} + // catch an error because the type might get changed, causing the parent to be removed from DOM + // however it's safe for us to ignore + } + async function present() { reminder.value = props.reminder; } + + watch(eventDelayPickerValue, () => { + reminder.value.delay = { + hours: eventDelayPickerValue.get('hours') || 0, + minutes: eventDelayPickerValue.get('minutes') || 0, + } + }); +