Skip to content

Commit

Permalink
feat: toasters
Browse files Browse the repository at this point in the history
  • Loading branch information
typicalninja committed Sep 9, 2023
1 parent 712bf27 commit da38302
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 56 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"dependencies": {
"@tanstack/svelte-query": "^4.35.0",
"axios": "^1.5.0",
"svelte-french-toast": "^1.2.0",
"svelte-local-storage-store": "^0.6.0"
}
}
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions src/components/DeleteConfirm.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script lang="ts">
import { fetchAPI } from '$lib/api';
import { typeToName, type DiscordInteraction } from '$lib/constants';
import { useQueryClient } from '@tanstack/svelte-query';
import toast_, { type Toast } from 'svelte-french-toast';
export let toast: Toast;
const queryClient = useQueryClient();
// @ts-ignore svelte-french-toast does not include props in latest version
const props: { cmd: DiscordInteraction; basePath: string; queryKey: string[] } = toast.props;
async function proceed() {
toast_.dismiss(toast.id)
try {
await toast_.promise(fetchAPI(`${props.basePath}/${props.cmd.id}`, { method: 'DELETE' }), {
success: `${typeToName(props.cmd.type)} successfully deleted`,
error: 'Error occurred, try again',
loading: 'Deletion pending...'
});
console.log('success');
queryClient.invalidateQueries({ queryKey: props.queryKey });
} catch (err) {
console.log(`Error while deleting [FORWARDED]`);
console.error(err);
}
}
</script>

<span>
Are you sure you want to, Delete "{props.cmd.name}" {typeToName(props.cmd.type)} Interaction?

<div class="flex gap-1 mt-1">
<button
class="p-2 rounded-lg bg-blurple-200 hover:bg-blurple-300"
on:click={() => toast_.dismiss(toast.id)}
>
Never mind
</button>
<button class="p-2 rounded-lg bg-red-200 hover:bg-red-300" on:click={proceed}>
Proceed with deletion
</button>
</div>
</span>
77 changes: 43 additions & 34 deletions src/components/commandList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
import { base } from '$app/paths';
import { fetchAPI } from '$lib/api';
import { typeToName, type DiscordInteraction } from '$lib/constants';
import { createQuery, useQueryClient } from '@tanstack/svelte-query';
import { createQuery } from '@tanstack/svelte-query';
import toast from 'svelte-french-toast';
import DeleteConfirm from './DeleteConfirm.svelte';
import { goto } from '$app/navigation';
// headers for the table
let headers: string[] = ['Name', 'Type', 'Description'];
// get basePath since same component can be used to get guild commands
export let basePath = '';
export let id = 'global';
const queryClient = useQueryClient();
$: queryKey = ['app.commands', id];
$: commandList = createQuery({
Expand All @@ -25,17 +27,13 @@
$: rows = $commandList.data || [];
async function deleteCommand(cmd: DiscordInteraction) {
if (confirm(`Do you want to delete command "${cmd.name}"?"`)) {
try {
await fetchAPI(`${basePath}/${cmd.id}`, { method: 'DELETE' });
queryClient.invalidateQueries({ queryKey });
alert(`Command: "${cmd.name}" was successfully deleted.`);
} catch (err) {
alert(`Error deleting command "${cmd.name}" [${err}]`);
console.log(`#DeleteCommandError`, err);
}
}
//@ts-ignore props are allowed in toasts
toast(DeleteConfirm, { props: { cmd, basePath, queryKey, duration: 6000, } });
}
</script>

<table class="bg-primary-400 rounded-t-lg min-w-full divide-y divide-primary-600">
Expand All @@ -50,22 +48,22 @@
{/each}
<th
scope="col"
class="px-6 py-3 text-left text-xs font-bold text-stone-400 uppercase tracking-wider"
class="px-6 py-3 text-xs font-bold text-stone-400 tracking-wider"
>
<button class="bg-primary-600 hover:bg-primary-500 rounded-full p-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="text-green-500"><path d="M5 12h14" /><path d="M12 5v14" /></svg
>
</button>
<button on:click={() => goto(`${base}/add${id === 'global' ? '' : `?guildId=${id}`}`)} class="bg-primary-600 hover:bg-primary-500 rounded-full p-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="text-green-500"><path d="M5 12h14" /><path d="M12 5v14" /></svg
>
</button>
</th>
</tr>
</thead>
Expand All @@ -80,15 +78,25 @@
{:else if error}
<tr>
<td colspan={headers.length} class="p-4">
<div class="w-max h-11 text-center mx-auto">
<p>(╯°□°)╯︵ ┻━┻</p>
<div class="w-max h-11 mx-auto flex flex-col justify-center items-center">
<p class="font-bold text-lg">(╯°□°)╯︵ ┻━┻</p>
<span class="text-red-400 font-bold">Oops! Something went wrong.</span>
</div>
</td>
</tr>
{:else}
<!-- Table content -->
{#each rows as row (row.id)}
{#if rows.length == 0}
<tr>
<td colspan={headers.length} class="p-4">
<div class="w-max h-11 mx-auto flex flex-col justify-center items-center">
<p class="font-bold text-lg">¯\_(ツ)_/¯</p>
<span class="text-yellow-200 font-bold">Nothing to display here.</span>
</div>
</td>
</tr>
{:else}
<!-- Table content -->
{#each rows as row (row.id)}
<tr>
<td class="px-4 py-4 whitespace-nowrap font-bold font-mono">{row.name}</td>
<td class="px-4 py-4 whitespace-nowrap font-semibold">{typeToName(row.type)}</td>
Expand Down Expand Up @@ -128,7 +136,8 @@
</button>
</td>
</tr>
{/each}
{/each}
{/if}
{/if}

<!-- Table bottom, status bar -->
Expand All @@ -150,7 +159,7 @@
d="M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2"
/></svg
>
{:else if !loading}
{:else if !loading && !error}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
Expand Down
Empty file added src/components/input.svelte
Empty file.
15 changes: 14 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,27 @@
import "../app.css";
import Header from '$components/header.svelte'
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
import { Toaster } from 'svelte-french-toast';
import { Urls } from "$lib/constants";
const queryClient = new QueryClient()
</script>


<QueryClientProvider client={queryClient}>
<div class="bg-primary-500 text-white min-h-screen flex flex-col gap-2 overflow-x-hidden">
<div class="hidden lg:flex bg-primary-500 text-white min-h-screen flex-col gap-2 overflow-x-hidden">
<Toaster position="bottom-right" />
<Header />
<slot />
</div>
<div class="lg:hidden p-2 bg-primary-500 text-white min-h-screen flex-col flex justify-center items-center">
<h1>Site unsupported!</h1>
<p>
You appear to be using a mobile device or browser with a minimized screen size
unfortunately we do not support this screen size.

Please use a desktop to access this site.
</p>
<a href={Urls.Github} class="text-blurple-500 underline">Github for issues</a>
</div>
</QueryClientProvider>
9 changes: 9 additions & 0 deletions src/routes/add/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import {browser} from "$app/environment";
import { base } from '$app/paths';
import { page } from '$app/stores';
</script>

<div class="m-2">
<h1 class="text-xl font-bold">Add</h1>
</div>
18 changes: 12 additions & 6 deletions src/routes/dashboard/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
import { goto } from '$app/navigation';
import {browser} from "$app/environment";
import { base } from '$app/paths';
import toast from 'svelte-french-toast';
const appInfo = get(applicationInfo);
$: searchParams = browser && $page.url.searchParams
$: guildId = searchParams && searchParams.get('guildId') || '';
$: guildId = searchParams && searchParams.get('guildId') || "global";
$: basePath =
guildId && discordIdRegex.test(guildId)
? `/applications/${appInfo.id}/guilds/${guildId}/commands`
Expand All @@ -20,10 +21,15 @@
let guildInput = '';
function viewGuildCommands() {
if (!discordIdRegex.test(guildInput)) return alert(`Invalid guild id`);
guildId = guildInput
if (!discordIdRegex.test(guildInput)) return toast.error(`The guild id is invalid, try again`)
toast(`Viewing guild "${guildInput}"`, {
icon: '🌏'
})
guildId = guildInput
goto(`?guildId=${guildInput}`);
}
</script>

<div class="m-5 flex flex-col gap-2">
Expand All @@ -36,7 +42,7 @@
</p>
</span>
<CommandList bind:id={guildId} {basePath} />
<div class="bg-blurple-900 flex flex-col p-2 rounded-lg gap-2">
<div class="bg-primary-900 flex flex-col p-2 rounded-lg gap-2">
{#if guildId && discordIdRegex.test(guildId)}
<h1>View Global List</h1>
<p>
Expand All @@ -50,7 +56,7 @@
<h1>View Guild commands</h1>
<p>
You are currently viewing the global list.
Enter a guild id (you bot must be invited to it)
Enter a guild id (your bot must be invited to it)
and click the button to manage guild specific interactions
</p>
<input
Expand All @@ -62,7 +68,7 @@
disabled={guildInput === ''}
class="{guildInput === ''
? 'bg-primary-600 cursor-not-allowed'
: 'bg-emerald-500 hover:bg-emerald-600'} p-2 rounded-lg">View guild commands</button
: 'bg-blurple-500 hover:bg-blurple-600'} p-2 rounded-lg">View Guild Interaction</button
>
{/if}
</div>
Expand Down
23 changes: 17 additions & 6 deletions src/routes/login/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { discordIdRegex } from '$lib/constants';
import { getAccessToken } from '$lib/api';
import { base } from '$app/paths';
import toast from 'svelte-french-toast';
let auth = get(authStore);
Expand All @@ -19,7 +20,9 @@
async function login() {
if(loginBlocked) return;
if(!discordIdRegex.test(clientId)) return alert(`Id is invalid.`)
if(!discordIdRegex.test(clientId)) {
throw new Error(`Client ID is invalid`)
}
loggingIn = true;
authStore.update((p) => ({ ...p, clientId, clientSecret }))
try {
Expand All @@ -35,15 +38,24 @@
id
});
goto(`${base}/dashboard`)
loggingIn = false;
return goto(`${base}/dashboard`)
}
catch(err) {
console.log('Error while verifying', err)
authStore.update((p) => ({ ...p, accessToken: '' }))
alert('Verification failed, try again (check your credentials)')
loggingIn = false;
throw new Error('Failed to login')
// alert('Verification failed, try again (check your credentials)')
}
}
loggingIn = false;
async function LoginWrapper() {
toast.promise(login(), {
loading: 'Logging in...',
success: 'Logged in, please wait...',
error: 'Could not log in, check your credentials',
})
}
onMount(() => {
Expand All @@ -65,7 +77,6 @@
<p>Get your application credentials from here <a href="https://discord.com/developers/applications" class="text-blurple-200 hover:underline">discord.com/developers/applications</a></p>
<input type="text" readonly={loggingIn} bind:value={clientId} placeholder="Client Id" class="bg-primary-500 rounded-md p-2 focus:ring-0 focus:ring-offset-0 focus:outline-none" />
<input type="password" readonly={loggingIn} bind:value={clientSecret} placeholder="Client Secret" class="bg-primary-500 rounded-md p-2 focus:ring-0 focus:ring-offset-0 focus:outline-none" />
<button on:click={login} disabled={loginBlocked || loggingIn} class="{loggingIn|| loginBlocked ? 'bg-primary-600 cursor-not-allowed' : 'bg-blurple-600 hover:bg-blurple-700'} p-2 rounded-lg">Login with token 🚀</button>
{#if loggingIn}<p>Please wait..., verifying credentials</p> {/if}
<button on:click={LoginWrapper} disabled={loginBlocked || loggingIn} class="{loggingIn|| loginBlocked ? 'bg-primary-600 cursor-not-allowed' : 'bg-blurple-600 hover:bg-blurple-700'} p-2 rounded-lg">Login with token 🚀</button>
</div>
</div>
Loading

0 comments on commit da38302

Please sign in to comment.