#41 add toasts and use for success and error #43

Merged
tim merged 1 commits from 41-toasts into master 2024-07-30 19:32:30 +00:00
5 changed files with 70 additions and 33 deletions

27
view/src/lib/toast.ts Normal file
View File

@@ -0,0 +1,27 @@
import { writable } from "svelte/store";
type Type = 'success' | 'info' | 'warning' | 'error';
type Toast = {
message: string;
type: Type;
}
const toastStore = writable<Toast[]>([]);
const addToast = (message: string, type: Type) => {
const newToast = { message, type };
toastStore.update((toasts) => {
return [...toasts, newToast];
});
setTimeout(() => {
toastStore.update((toasts) => toasts.filter((t) => t !== newToast));
}, 5000);
}
export { toastStore, addToast, };
export type { Toast }

View File

@@ -2,29 +2,38 @@
import '../app.css'; import '../app.css';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import type { Auth, User } from 'firebase/auth'; import type { Auth, User } from 'firebase/auth';
import { addToast, toastStore } from '$lib/toast';
import type { Toast } from '$lib/toast';
var auth: Auth | null = null; var auth: Auth | null = null;
var user: User | null = null; var user: User | null = null;
var unsub: (() => void) | null = null; var unsubAuth: (() => void) | null = null;
let toasts: Toast[] = [];
let unsubToast = toastStore.subscribe((value) => {
toasts = value;
});
onMount(async () => { onMount(async () => {
const { auth: _auth } = await import('../lib/firebase'); const { auth: _auth } = await import('../lib/firebase');
auth = _auth; auth = _auth;
user = auth.currentUser; user = auth.currentUser;
unsub = auth.onAuthStateChanged((newUser) => { unsubAuth = auth.onAuthStateChanged((newUser) => {
user = newUser; user = newUser;
}); });
}); });
onDestroy(() => { onDestroy(() => {
if (unsub) { unsubToast();
unsub(); if (unsubAuth) {
unsubAuth();
} }
}); });
const signOut = async () => { const signOut = async () => {
try { try {
await (auth as Auth).signOut(); await (auth as Auth).signOut();
addToast('Signed out successfully', 'success');
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@@ -46,4 +55,21 @@
<div class="flex-1"> <div class="flex-1">
<slot></slot> <slot></slot>
</div> </div>
<!-- This is needed so all class names are inside the bundle -->
<!-- The class names are used dynamically, so tailwind can't know -->
<div class="hidden">
<div class="alert-info text-info-content"></div>
<div class="alert-success text-success-content"></div>
<div class="alert-warning text-warning-content"></div>
<div class="alert-error text-error-content"></div>
</div>
<div class="toast toast-end">
{#each toasts as toast}
<div class="alert alert-{toast.type}">
<span class="text-{toast.type}-content">{toast.message}</span>
</div>
{/each}
</div>
</div> </div>

View File

@@ -3,8 +3,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import type { Auth } from 'firebase/auth'; import type { Auth } from 'firebase/auth';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { addToast } from '$lib/toast';
$: errorStr = '';
var auth: Auth | null = null; var auth: Auth | null = null;
@@ -12,8 +11,6 @@
$: workouts = []; $: workouts = [];
async function handleSubmit(_submit: SubmitEvent) { async function handleSubmit(_submit: SubmitEvent) {
errorStr = '';
const form = _submit.target as HTMLFormElement; const form = _submit.target as HTMLFormElement;
const formData = new FormData(form); const formData = new FormData(form);
@@ -30,12 +27,10 @@
fetchWorkouts(); fetchWorkouts();
resetForm(); resetForm();
} else { } else {
const data = await response.text(); addToast('Failed to save workout: ' + (await response.text()), 'error');
errorStr = data;
} }
} catch (error: any) { } catch (error: any) {
errorStr = error.message; addToast('Failed to save workout: ' + error.message, 'error');
console.error(error);
} }
} }
@@ -62,10 +57,10 @@
console.log(data); console.log(data);
workouts = data; workouts = data;
} else { } else {
errorStr = await response.text(); addToast('Failed to fetch workouts: ' + (await response.text()), 'error');
} }
} catch (error: any) { } catch (error: any) {
console.log(error); addToast('Failed to fetch workouts: ' + error.message, 'error');
} }
} }
@@ -101,9 +96,6 @@
<input type="number" class="input input-bordered" placeholder="Reps" name="reps" /> <input type="number" class="input input-bordered" placeholder="Reps" name="reps" />
<button class="btn btn-primary self-end">Save</button> <button class="btn btn-primary self-end">Save</button>
{#if errorStr}
<p class="text-error">{errorStr}</p>
{/if}
</form> </form>
<div class="overflow-x-auto mx-auto max-w-screen-lg"> <div class="overflow-x-auto mx-auto max-w-screen-lg">

View File

@@ -1,11 +1,9 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { addToast } from '$lib/toast';
import { signInWithEmailAndPassword } from 'firebase/auth'; import { signInWithEmailAndPassword } from 'firebase/auth';
var errorStr: string | null = null;
const signIn = async (event: SubmitEvent) => { const signIn = async (event: SubmitEvent) => {
errorStr = null;
const { auth } = await import('$lib/firebase'); const { auth } = await import('$lib/firebase');
try { try {
@@ -16,9 +14,11 @@
data.get('password') as string data.get('password') as string
); );
addToast('Signed in successfully', 'success');
goto('/'); goto('/');
} catch (error: any) { } catch (error: any) {
errorStr = error.code ? error.code : error.message; const errorStr = error.code ? error.code : error.message;
addToast('Failed to sign in: ' + errorStr, 'error');
} }
}; };
</script> </script>
@@ -65,8 +65,4 @@
<a href="/signup" class="link gray-500">Sign Up</a> <a href="/signup" class="link gray-500">Sign Up</a>
<button class="btn btn-primary self-end">Sign In</button> <button class="btn btn-primary self-end">Sign In</button>
</div> </div>
{#if errorStr}
<p class="text-red-500">{errorStr}</p>
{/if}
</form> </form>

View File

@@ -1,11 +1,9 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { addToast } from '$lib/toast';
import { createUserWithEmailAndPassword } from 'firebase/auth'; import { createUserWithEmailAndPassword } from 'firebase/auth';
var errorStr: string | null = null;
const signUp = async (event: SubmitEvent) => { const signUp = async (event: SubmitEvent) => {
errorStr = null;
const { auth } = await import('$lib/firebase'); const { auth } = await import('$lib/firebase');
try { try {
@@ -16,9 +14,11 @@
data.get('password') as string data.get('password') as string
); );
addToast('Signed up successfully', 'success');
goto('/'); goto('/');
} catch (error: any) { } catch (error: any) {
errorStr = error.code ? error.code : error.message; const errorStr = error.code ? error.code : error.message;
addToast('Failed to sign up: ' + errorStr, 'error');
} }
}; };
</script> </script>
@@ -65,8 +65,4 @@
<a href="/signin" class="link gray-500">Sign In</a> <a href="/signin" class="link gray-500">Sign In</a>
<button class="btn btn-primary self-end">Sign Up</button> <button class="btn btn-primary self-end">Sign Up</button>
</div> </div>
{#if errorStr}
<p class="text-red-500">{errorStr}</p>
{/if}
</form> </form>