diff --git a/.gitignore b/.gitignore
index ea06162..e1d9e77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ node_modules
.env
.env.*
!.env.example
+.idea/
# Supabase CLI information
supabase
diff --git a/src/lib/components/_spinner.svelte b/src/lib/components/_spinner.svelte
new file mode 100644
index 0000000..ec7ba7c
--- /dev/null
+++ b/src/lib/components/_spinner.svelte
@@ -0,0 +1,12 @@
+
+
diff --git a/src/routes/admin/events/+page.svelte b/src/routes/admin/events/+page.svelte
new file mode 100644
index 0000000..f31d336
--- /dev/null
+++ b/src/routes/admin/events/+page.svelte
@@ -0,0 +1,162 @@
+
+
+
+ All Events
+
+ {#if $isLoading}
+
+
+
+ {:else}
+
+
+
+
+
+ ID |
+ Title |
+ Date |
+ End Date |
+ Status |
+ Actions |
+
+
+
+ {#each $events as event (event.id)}
+
+ {event.id} |
+ {event.title} |
+ {formatDate(event.date)} |
+ {formatDate(event.end_date)} |
+ {getState(event)} |
+
+
+
+
+
+
+
+
+
+
+ |
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/api/events/+server.ts b/src/routes/api/events/+server.ts
index 92ae312..65d0ab2 100644
--- a/src/routes/api/events/+server.ts
+++ b/src/routes/api/events/+server.ts
@@ -1,35 +1,85 @@
-import { error, json } from "@sveltejs/kit";
+import { error, json, type RequestEvent } from "@sveltejs/kit"
import type { RequestHandler } from "@sveltejs/kit";
import { getSupabase } from "@supabase/auth-helpers-sveltekit";
import { formatISO } from "date-fns";
import { SUPABASE_TABLE_NAME } from '$env/static/private'
+const DEFAULT_VERSION = 1;
+const DEFAULT_PAGE_SIZE = 25;
+const MAX_PAGE_SIZE = 25;
+
+const SUPPORTED_ORDER_BY = ["date", "id"];
+const SUPPORTED_VERSIONS = [1, 2];
export const GET: RequestHandler = async (request) => {
const { supabaseClient } = await getSupabase(request);
- const { url: { searchParams }, setHeaders } = request;
-
- let pageNum = Number.parseInt(searchParams.get("page"), 10) || 1;
- pageNum = pageNum < 1 ? 1 : pageNum;
-
- const DATES_PAGE_SIZE = 25;
+ const { setHeaders } = request;
+ const filters = getRequestFilters(request);
let query = supabaseClient.from(SUPABASE_TABLE_NAME)
- .select("*")
- .order("priority", {ascending: false})
- .order("date", {ascending: true})
+ .select("*", { count: filters.version === 2 ? "exact" : undefined })
- const includePast = searchParams.get("include_past") === "true";
- if (!includePast) { query = query.or(`date.gte.${formatISO(new Date())},end_date.gte.${formatISO(new Date())},date.is.null`) }
+ // if there is no order by, use the default sort of priority and date which is used by the homepage
+ if (!filters.orderBy) {
+ query = query
+ .order("priority", { ascending: false })
+ .order("date", { ascending: true })
+ } else {
+ query = query.order(filters.orderBy, { ascending: filters.orderDirection === "asc" })
+ }
+
+ // if we aren't including past events, limit the query to only events that are currently happening or in the future
+ if (!filters.includePast) {
+ query = query.or(`date.gte.${formatISO(new Date())},end_date.gte.${formatISO(new Date())},date.is.null`)
+ }
- query = query.range((pageNum - 1) * DATES_PAGE_SIZE, (pageNum * DATES_PAGE_SIZE) - 1);
+ query = query.range((filters.pageNum - 1) * filters.pageSize, (filters.pageNum * filters.pageSize) - 1);
- const { data, error: err } = await query;
+ const { data, error: err, count, status } = await query;
if (err) throw error(500, "Database error");
setHeaders({
"cache-control": "public, max-age=60"
})
+
+ if (filters.version === 2) {
+ return json({
+ meta: {
+ total: count,
+ total_pages: Math.ceil(count / filters.pageSize)
+ },
+ data
+ });
+ }
+
return json(data);
}
+
+function getRequestFilters (request: RequestEvent) {
+ const searchParams = request.url.searchParams;
+
+ let version = Number.parseInt(searchParams.get("v"), 10);
+ version = SUPPORTED_VERSIONS.includes(version) ? version : DEFAULT_VERSION;
+
+ let orderBy = searchParams.get("order_by");
+ orderBy = SUPPORTED_ORDER_BY.includes(orderBy) ? orderBy : null;
+
+ let pageNum = Number.parseInt(searchParams.get("page"), 10) || 1;
+ pageNum = pageNum < 1 ? 1 : pageNum;
+
+ let pageSize = Number.parseInt(searchParams.get("page_size"), 10) || DEFAULT_PAGE_SIZE;
+ pageSize = (pageSize < 1 || pageSize > MAX_PAGE_SIZE) ? DEFAULT_PAGE_SIZE : pageSize;
+
+ const orderDirection = searchParams.get("order_direction") === "desc" ? "desc" : "asc";
+ const includePast = searchParams.get("include_past") === "true";
+
+ return {
+ version,
+ orderBy,
+ pageNum,
+ pageSize,
+ orderDirection,
+ includePast
+ }
+}