Skip to content

Commit

Permalink
Merge pull request #82 from aleksasiriski/as/fix/search-post
Browse files Browse the repository at this point in the history
fix(search): POST and toast for toggle
  • Loading branch information
aleksasiriski authored Dec 25, 2024
2 parents 38382f4 + b8ac77c commit e0451f3
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 31 deletions.
2 changes: 2 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ services:
build:
context: .
dockerfile: docker/postgres.Dockerfile
ports:
- 5432:5432
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ services:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- './database:/var/lib/postgresql/data:z'
restart: never
2 changes: 0 additions & 2 deletions src/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import type { Database } from '$lib/server/db/connect';
import type { User } from '$lib/server/db/schema/user';
import type { Session } from '$lib/server/db/schema/session';

declare global {
namespace App {
interface Locals {
database: Database;
user: User | null;
session: Session | null;
}
Expand Down
1 change: 1 addition & 0 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const handle: Handle = async ({ event, resolve }) => {
} else {
// If session is invalid, delete the session cookie
deleteSessionTokenCookie(event);

// Redirect to the login page after session expiry
if (event.url.pathname !== '/login') {
return redirect(302, '/login');
Expand Down
2 changes: 1 addition & 1 deletion src/lib/server/db/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { env } from '$env/dynamic/private';
import { connectDatabaseWithURL } from './connect_generic';

export type Database = PostgresJsDatabase<Record<string, never>>;
export type Client = postgres.Sql<{}>;
export type Client = postgres.Sql<{}>; // eslint-disable-line @typescript-eslint/no-empty-object-type

// Connects to the database using the DATABASE_URL environment variable
export async function connectDatabase(): Promise<{
Expand Down
58 changes: 52 additions & 6 deletions src/routes/(dashboard)/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { Employee, Student, type Person } from '$lib/types/person';
import { invalidateSession } from '$lib/server/db/session';
import { deleteSessionTokenCookie } from '$lib/server/session';

export const load: PageServerLoad = async ({ url }) => {
export const load: PageServerLoad = async () => {
try {
const searchQuery = url.searchParams.get('q') ?? undefined;
const studentsP = getStudents(1000, 0, searchQuery);
const employeesP = getEmployees(1000, 0, searchQuery);
const studentsP = getStudents(1000, 0);
const employeesP = getEmployees(1000, 0);
const students = await studentsP;
const employees = await employeesP;

Expand Down Expand Up @@ -38,7 +37,6 @@ export const load: PageServerLoad = async ({ url }) => {
];

return {
searchQuery,
persons
};
} catch (err: unknown) {
Expand All @@ -50,6 +48,50 @@ export const load: PageServerLoad = async ({ url }) => {
};

export const actions: Actions = {
search: async ({ request }) => {
try {
const formData = await request.formData();
const searchQuery = formData.get('q')?.toString() ?? undefined;

const studentsP = getStudents(1000, 0, searchQuery);
const employeesP = getEmployees(1000, 0, searchQuery);
const students = await studentsP;
const employees = await employeesP;

const persons: Person[] = [
...students.map((s) => ({
id: s.id,
type: Student,
identifier: s.index,
fname: s.fname,
lname: s.lname,
department: s.department,
building: s.building,
state: s.state
})),
...employees.map((e) => ({
id: e.id,
type: Employee,
identifier: e.email,
fname: e.fname,
lname: e.lname,
department: e.department,
building: e.building,
state: e.state
}))
];

return {
searchQuery,
persons
};
} catch (err: unknown) {
console.debug(`Failed to search: ${(err as Error).message}`);
return fail(500, {
message: 'Failed to search'
});
}
},
togglestate: async ({ request, locals }) => {
try {
const formData = await request.formData();
Expand Down Expand Up @@ -86,10 +128,14 @@ export const actions: Actions = {
} else if (type === Employee) {
await toggleEmployeeState(id, building, creator);
} else {
return fail(400, {
return fail(500, {
message: 'Invalid type (neither student nor employee)'
});
}

return {
message: 'Successfully toggled state'
};
} catch (err: unknown) {
console.debug(`Failed to toggle state: ${(err as Error).message}`);
return fail(400, {
Expand Down
55 changes: 38 additions & 17 deletions src/routes/(dashboard)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,54 @@
import Search from 'lucide-svelte/icons/search';
import Reset from 'lucide-svelte/icons/list-restart';
import DataTable from './data-table.svelte';
import { toast } from 'svelte-sonner';
import { page } from '$app/stores';
import { columns } from './columns';
import { enhance } from '$app/forms';
import { goto } from '$app/navigation';
let { data, form: actionData } = $props();
const searchQuery = data.searchQuery;
let searchBox: HTMLFormElement | null;
$effect(() => {
const msg = actionData?.message;
if (msg !== undefined) {
if ($page.status === 200) {
toast.success(msg);
} else {
toast.error(msg);
}
}
});
let searchQuery = $state('');
const persons = $derived(actionData?.persons ?? data.persons ?? []);
</script>

<form
action="/"
bind:this={searchBox}
onreset={() => {
searchBox?.submit();
method="POST"
action="?/search"
class="flex gap-2 px-4 py-2"
use:enhance={() => {
return async ({ update }) => {
await update({ reset: false });
};
}}
>
<div class="flex gap-2 px-4 py-2">
<Input id="search" class="max-w-xs" placeholder="Search..." name="q" value={searchQuery} />
<Button type="submit" size="icon" class="flex-shrink-0">
<Search />
</Button>
<Button type="reset" variant="destructive" size="icon" class="flex-shrink-0">
<Reset />
</Button>
<p class="my-auto text-rose-600 dark:text-rose-500">{actionData?.message}</p>
</div>
<Input id="search" class="max-w-xs" placeholder="Search..." name="q" bind:value={searchQuery} />
<Button type="submit" size="icon" class="flex-shrink-0">
<Search />
</Button>
<Button
onclick={() => goto('/')}
type="reset"
variant="destructive"
size="icon"
class="flex-shrink-0"
>
<Reset />
</Button>
</form>
<Separator />
<div class="m-0 sm:m-4">
<DataTable data={data.persons ?? []} {columns} />
<DataTable data={persons} {columns} />
</div>
11 changes: 6 additions & 5 deletions src/routes/(dashboard)/data-table.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script lang="ts" generics="TData, TValue">
<script lang="ts">
import {
type ColumnDef,
getCoreRowModel,
Expand All @@ -10,13 +10,14 @@
import { createSvelteTable, FlexRender } from '$lib/components/ui/data-table/index.js';
import * as Table from '$lib/components/ui/table/index.js';
import Button from '$lib/components/ui/button/button.svelte';
import type { Person } from '$lib/types/person';
type DataTableProps<TData, TValue> = {
columns: ColumnDef<TData, TValue>[];
data: TData[];
type DataTableProps<Person> = {
columns: ColumnDef<Person>[];
data: Person[];
};
let { data, columns }: DataTableProps<TData, TValue> = $props();
let { data, columns }: DataTableProps<Person> = $props();
let pagination = $state<PaginationState>({ pageIndex: 0, pageSize: 10 });
let sorting = $state<SortingState>([]);
Expand Down

0 comments on commit e0451f3

Please sign in to comment.