diff --git a/package.json b/package.json
index 60918e7..8c88391 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "homepage",
- "version": "1.13.4",
+ "version": "1.14.0",
"private": true,
"type": "module",
"scripts": {
diff --git a/src/lib/components/ConfirmDialog.svelte b/src/lib/components/ConfirmDialog.svelte
new file mode 100644
index 0000000..cd58dd2
--- /dev/null
+++ b/src/lib/components/ConfirmDialog.svelte
@@ -0,0 +1,108 @@
+
+
+
+
+{#if dialog.open}
+
dialog.respond(false)} role="presentation">
+
e.stopPropagation()} role="alertdialog" aria-modal="true">
+ {#if dialog.title}
+
{dialog.title}
+ {/if}
+
{dialog.message}
+
+
+
+
+
+
+{/if}
+
+
diff --git a/src/lib/components/cospend/PaymentModal.svelte b/src/lib/components/cospend/PaymentModal.svelte
index 198a801..17a842f 100644
--- a/src/lib/components/cospend/PaymentModal.svelte
+++ b/src/lib/components/cospend/PaymentModal.svelte
@@ -7,6 +7,7 @@
import { getCategoryEmoji } from '$lib/utils/categories';
import { formatCurrency as formatCurrencyUtil } from '$lib/utils/formatters';
import { detectCospendLang, cospendRoot, t, locale, splitDescription, paymentCategoryName } from '$lib/js/cospendI18n';
+ import { confirm } from '$lib/js/confirmDialog.svelte';
let { paymentId, onclose, onpaymentDeleted } = $props();
@@ -110,7 +111,7 @@
let deleting = $state(false);
async function deletePayment() {
- if (!confirm(t('delete_payment_confirm', lang))) {
+ if (!await confirm(t('delete_payment_confirm', lang))) {
return;
}
diff --git a/src/lib/components/fitness/PeriodTracker.svelte b/src/lib/components/fitness/PeriodTracker.svelte
index d06e9c1..684870a 100644
--- a/src/lib/components/fitness/PeriodTracker.svelte
+++ b/src/lib/components/fitness/PeriodTracker.svelte
@@ -2,6 +2,7 @@
import { t } from '$lib/js/fitnessI18n';
import { Trash2, Plus, Pencil, UserPlus, X, ChevronLeft, ChevronRight } from '@lucide/svelte';
import { toast } from '$lib/js/toast.svelte';
+ import { confirm } from '$lib/js/confirmDialog.svelte';
import ProfilePicture from '$lib/components/cospend/ProfilePicture.svelte';
/**
@@ -523,7 +524,7 @@
/** @param {string} id */
async function deletePeriod(id) {
- if (!confirm(t('delete_period_confirm', lang))) return;
+ if (!await confirm(t('delete_period_confirm', lang))) return;
try {
const res = await fetch(`/api/fitness/period/${id}`, { method: 'DELETE' });
if (res.ok) {
diff --git a/src/lib/components/recipes/CreateIngredientList.svelte b/src/lib/components/recipes/CreateIngredientList.svelte
index 6acda7f..25bbfce 100644
--- a/src/lib/components/recipes/CreateIngredientList.svelte
+++ b/src/lib/components/recipes/CreateIngredientList.svelte
@@ -7,6 +7,7 @@ import Plus from '$lib/assets/icons/Plus.svelte'
import Check from '$lib/assets/icons/Check.svelte'
import "$lib/css/action_button.css"
+import { confirm } from '$lib/js/confirmDialog.svelte'
import { do_on_key } from '$lib/components/recipes/do_on_key.js'
import { portions } from '$lib/js/portions_store.js'
@@ -138,8 +139,8 @@ function handleSelect(recipe: any, options: any) {
showSelector = false;
}
-export function removeReference(list_index: number) {
- const confirmed = confirm(t[lang].confirmDeleteReference);
+export async function removeReference(list_index: number) {
+ const confirmed = await confirm(t[lang].confirmDeleteReference);
if (confirmed) {
ingredients.splice(list_index, 1);
ingredients = ingredients;
@@ -265,9 +266,9 @@ export function add_new_ingredient(){
ingredients[list_index].list.push({ ...new_ingredient})
ingredients = ingredients //tells svelte to update dom
}
-export function remove_list(list_index: number){
+export async function remove_list(list_index: number){
if(ingredients[list_index].list.length > 1){
- const response = confirm(t[lang].confirmDeleteList);
+ const response = await confirm(t[lang].confirmDeleteList);
if(!response){
return
}
diff --git a/src/lib/components/recipes/CreateStepList.svelte b/src/lib/components/recipes/CreateStepList.svelte
index 399c2d3..8baddd9 100644
--- a/src/lib/components/recipes/CreateStepList.svelte
+++ b/src/lib/components/recipes/CreateStepList.svelte
@@ -8,6 +8,7 @@ import Check from '$lib/assets/icons/Check.svelte'
import "$lib/css/action_button.css"
import { do_on_key } from '$lib/components/recipes/do_on_key.js'
+import { confirm } from '$lib/js/confirmDialog.svelte'
import BaseRecipeSelector from '$lib/components/recipes/BaseRecipeSelector.svelte'
let { lang = 'de' as 'de' | 'en', instructions = $bindable(), add_info = $bindable() } = $props<{ lang?: 'de' | 'en', instructions: any, add_info: any }>();
@@ -134,8 +135,8 @@ function handleSelect(recipe: any, options: any) {
showSelector = false;
}
-export function removeReference(list_index: number) {
- const confirmed = confirm(t[lang].confirmDeleteReference);
+export async function removeReference(list_index: number) {
+ const confirmed = await confirm(t[lang].confirmDeleteReference);
if (confirmed) {
instructions.splice(list_index, 1);
instructions = instructions;
@@ -219,9 +220,9 @@ function get_sublist_index(sublist_name: string, list: any[]){
}
return -1
}
-export function remove_list(list_index: number){
+export async function remove_list(list_index: number){
if(instructions[list_index].steps.length > 1){
- const response = confirm(t[lang].confirmDeleteList);
+ const response = await confirm(t[lang].confirmDeleteList);
if(!response){
return
}
diff --git a/src/lib/js/confirmDialog.svelte.ts b/src/lib/js/confirmDialog.svelte.ts
new file mode 100644
index 0000000..13473dc
--- /dev/null
+++ b/src/lib/js/confirmDialog.svelte.ts
@@ -0,0 +1,55 @@
+interface ConfirmState {
+ open: boolean;
+ title: string;
+ message: string;
+ confirmText: string;
+ cancelText: string;
+ destructive: boolean;
+ resolve: ((value: boolean) => void) | null;
+}
+
+let state = $state({
+ open: false,
+ title: '',
+ message: '',
+ confirmText: 'OK',
+ cancelText: 'Cancel',
+ destructive: false,
+ resolve: null,
+});
+
+export function getConfirmDialog() {
+ return {
+ get open() { return state.open; },
+ get title() { return state.title; },
+ get message() { return state.message; },
+ get confirmText() { return state.confirmText; },
+ get cancelText() { return state.cancelText; },
+ get destructive() { return state.destructive; },
+ respond(value: boolean) {
+ state.resolve?.(value);
+ state = { ...state, open: false, resolve: null };
+ }
+ };
+}
+
+interface ConfirmOptions {
+ title?: string;
+ confirmText?: string;
+ cancelText?: string;
+ destructive?: boolean;
+}
+
+export function confirm(message: string, options: ConfirmOptions = {}): Promise {
+ return new Promise((resolve) => {
+ state = {
+ open: true,
+ message,
+ title: options.title ?? '',
+ confirmText: options.confirmText ?? 'OK',
+ cancelText: options.cancelText ?? 'Cancel',
+ destructive: options.destructive ?? true,
+ resolve,
+ };
+ });
+}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 507e105..8b30a0e 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -2,6 +2,7 @@
import '../app.css';
import { onNavigate } from '$app/navigation';
import Toast from '$lib/components/Toast.svelte';
+ import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
let { children } = $props();
onNavigate((navigation) => {
@@ -22,4 +23,5 @@
{@render children()}
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/src/routes/[cospendRoot=cospendRoot]/payments/+page.svelte b/src/routes/[cospendRoot=cospendRoot]/payments/+page.svelte
index c1e788b..ce0578a 100644
--- a/src/routes/[cospendRoot=cospendRoot]/payments/+page.svelte
+++ b/src/routes/[cospendRoot=cospendRoot]/payments/+page.svelte
@@ -5,6 +5,7 @@
import ProfilePicture from '$lib/components/cospend/ProfilePicture.svelte';
import { getCategoryEmoji } from '$lib/utils/categories';
import { toast } from '$lib/js/toast.svelte';
+ import { confirm } from '$lib/js/confirmDialog.svelte';
import { isSettlementPayment, getSettlementIcon, getSettlementReceiver } from '$lib/utils/settlements';
import AddButton from '$lib/components/AddButton.svelte';
import { detectCospendLang, cospendRoot, t, locale, splitDescription, paymentCategoryName } from '$lib/js/cospendI18n';
@@ -82,7 +83,7 @@
}
async function deletePayment(/** @type {string} */ paymentId) {
- if (!confirm(t('delete_payment_confirm', lang))) {
+ if (!await confirm(t('delete_payment_confirm', lang))) {
return;
}
diff --git a/src/routes/[cospendRoot=cospendRoot]/payments/edit/[id]/+page.svelte b/src/routes/[cospendRoot=cospendRoot]/payments/edit/[id]/+page.svelte
index 8d8cff2..64e9307 100644
--- a/src/routes/[cospendRoot=cospendRoot]/payments/edit/[id]/+page.svelte
+++ b/src/routes/[cospendRoot=cospendRoot]/payments/edit/[id]/+page.svelte
@@ -3,6 +3,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { detectCospendLang, cospendRoot, locale, t, getCategoryOptionsI18n } from '$lib/js/cospendI18n';
+ import { confirm } from '$lib/js/confirmDialog.svelte';
import FormSection from '$lib/components/FormSection.svelte';
import ImageUpload from '$lib/components/ImageUpload.svelte';
import SaveFab from '$lib/components/SaveFab.svelte';
@@ -264,7 +265,7 @@
let deleting = $state(false);
async function deletePayment() {
- if (!confirm('Are you sure you want to delete this payment? This action cannot be undone.')) {
+ if (!await confirm('Are you sure you want to delete this payment? This action cannot be undone.')) {
return;
}
diff --git a/src/routes/[cospendRoot=cospendRoot]/recurring/+page.svelte b/src/routes/[cospendRoot=cospendRoot]/recurring/+page.svelte
index 1873e7a..4a3a47c 100644
--- a/src/routes/[cospendRoot=cospendRoot]/recurring/+page.svelte
+++ b/src/routes/[cospendRoot=cospendRoot]/recurring/+page.svelte
@@ -3,6 +3,7 @@
import { getCategoryEmoji } from '$lib/utils/categories';
import ProfilePicture from '$lib/components/cospend/ProfilePicture.svelte';
import { toast } from '$lib/js/toast.svelte';
+ import { confirm } from '$lib/js/confirmDialog.svelte';
import AddButton from '$lib/components/AddButton.svelte';
import { formatCurrency } from '$lib/utils/formatters';
import Toggle from '$lib/components/Toggle.svelte';
@@ -65,7 +66,7 @@
}
async function deleteRecurringPayment(/** @type {string} */ paymentId, /** @type {string} */ title) {
- if (!confirm(`${t('delete_recurring_confirm', lang)} "${title}"?`)) {
+ if (!await confirm(`${t('delete_recurring_confirm', lang)} "${title}"?`)) {
return;
}
diff --git a/src/routes/[recipeLang=recipeLang]/to-try/+page.svelte b/src/routes/[recipeLang=recipeLang]/to-try/+page.svelte
index d3c690a..840b4dd 100644
--- a/src/routes/[recipeLang=recipeLang]/to-try/+page.svelte
+++ b/src/routes/[recipeLang=recipeLang]/to-try/+page.svelte
@@ -1,5 +1,6 @@