diff --git a/.github/workflows/main.yaml b/.github/workflows/update-remote-database.yaml similarity index 87% rename from .github/workflows/main.yaml rename to .github/workflows/update-remote-database.yaml index 51cce57..93e8996 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/update-remote-database.yaml @@ -1,4 +1,4 @@ -name: Release (Production) +name: Update Remote Database on: push: @@ -21,4 +21,4 @@ jobs: version: latest - run: supabase link --project-ref $SUPABASE_PROJECT_ID - - run: supabase db push \ No newline at end of file + - run: supabase db push --include-all diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..6c6067f --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +supabase/migrations \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..93c54d9 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,21 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "jsxSingleQuote": false, + "arrowParens": "always", + "plugins": ["prettier-plugin-sql"], + "overrides": [ + { + "files": "*.sql", + "options": { + "language": "postgresql", + "keywordCase": "lower", + "dataTypeCase": "lower" + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9bf4d12 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true +} diff --git a/app/(pages)/example/page.tsx b/app/(pages)/example/page.tsx deleted file mode 100644 index bffadf2..0000000 --- a/app/(pages)/example/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client"; - -import { createExampleEntry } from "@/app/api/example/actions"; -import { ExampleType } from "@/app/types/ExampleType"; - -export default function Example() { - const data: ExampleType = { - id: 5, - name: 'harry', - }; - - const handleExampleClick = async () => { - await createExampleEntry(data); - }; - - return ( -
- Welcome to PATH! This is an example page. -
- -
- ); -} \ No newline at end of file diff --git a/app/(pages)/test/page.tsx b/app/(pages)/test/page.tsx new file mode 100644 index 0000000..3a3df0a --- /dev/null +++ b/app/(pages)/test/page.tsx @@ -0,0 +1,23 @@ +'use client'; + +import ExampleTestComponent from '@/app/components/test/ExampleTestComponent'; +import DonationsTestComponent from '@/app/components/test/DonationsTestComponent'; +import StoresTestComponent from '@/app/components/test/StoresTestComponent'; +import InventoryItemsTestComponent from '@/app/components/test/InventoryItemsTestComponent'; +import TicketsTestComponent from '@/app/components/test/TicketsTestComponent'; +import TicketItemsTestComponent from '@/app/components/test/TicketItemsTestComponent'; + +export default function TestPage() { + return ( +
+ Welcome to PATH! This is a test page. +
+ + + + + + +
+ ); +} diff --git a/app/api/donations/actions.ts b/app/api/donations/actions.ts new file mode 100644 index 0000000..2260a0b --- /dev/null +++ b/app/api/donations/actions.ts @@ -0,0 +1,36 @@ +'use server'; + +import { DonationInsert } from '@/app/types/donation'; +import { createClient } from '@/app/lib/supabase/server-client'; + +export async function createDonation(data: DonationInsert) { + const supabase = await createClient(); + + const { data: entry, error: err } = await supabase + .from('donations') + .insert(data) + .select() // after inserting, return full new row + .single(); // expect just one row, if more or less, throw an error + + if (err) { + console.error('Error creating donation:', err); + return { success: false, error: err }; + } + return { success: true, data: entry }; // return the row that was created +} + +// deletes donation based on donation_id +export async function deleteDonation(donationId: string) { + const supabase = await createClient(); + + const { error: err } = await supabase + .from('donations') + .delete() + .eq('donation_id', donationId); + + if (err) { + console.error('Error deleting donation:', err); + return { success: false, error: err }; + } + return { success: true }; +} diff --git a/app/api/example/actions.ts b/app/api/example/actions.ts index db2c0cb..3d5b37d 100644 --- a/app/api/example/actions.ts +++ b/app/api/example/actions.ts @@ -1,14 +1,19 @@ -"use server"; +'use server'; -import { ExampleType } from "@/app/types/ExampleType"; -import { createClient } from "@/app/lib/supabase/server-client"; +import { Example } from '@/app/types/example'; +import { createClient } from '@/app/lib/supabase/server-client'; -export const createExampleEntry = async (data: ExampleType) => { +export const createExampleEntry = async (data: Example) => { const supabase = await createClient(); - const { data: entry, error } = await supabase.from("example").insert(data); + const { data: entry, error: err } = await supabase + .from('example') + .insert(data) + .select() + .single(); - if (error) { - throw error; + if (err) { + console.error('Error creating example:', err); + return { success: false, error: err }; } - return entry; -} \ No newline at end of file + return { success: true, data: entry }; +}; diff --git a/app/api/inventory-items/actions.ts b/app/api/inventory-items/actions.ts new file mode 100644 index 0000000..0004462 --- /dev/null +++ b/app/api/inventory-items/actions.ts @@ -0,0 +1,50 @@ +'use server'; + +import { InventoryItemInsert } from '@/app/types/inventory'; +import { createClient } from '@/app/lib/supabase/server-client'; + +export const createItem = async (data: InventoryItemInsert) => { + const supabase = await createClient(); + const { data: entry, error: err } = await supabase + .from('inventory_items') + .insert(data) + .select() + .single(); + + if (err) { + console.error('Error creating inventory item:', err); + return { success: false, error: err }; + } + return { success: true, data: entry }; +}; + +export const changeItemQuantity = async ( + inventoryItemId: string, + newQuantity: number, +) => { + const supabase = await createClient(); + const { error: err } = await supabase + .from('inventory_items') + .update({ quantity_available: newQuantity }) + .eq('inventory_item_id', inventoryItemId); + + if (err) { + console.error('Error changing inventory item quantity:', err); + return { success: false, error: err }; + } + return { success: true }; +}; + +export const deleteItem = async (inventoryItemId: string) => { + const supabase = await createClient(); + const { error: err } = await supabase + .from('inventory_items') + .delete() + .eq('inventory_item_id', inventoryItemId); + + if (err) { + console.error('Error deleting inventory item:', err); + return { success: false, error: err }; + } + return { success: true }; +}; diff --git a/app/api/stores/actions.ts b/app/api/stores/actions.ts new file mode 100644 index 0000000..0fb4718 --- /dev/null +++ b/app/api/stores/actions.ts @@ -0,0 +1,35 @@ +'use server'; + +import { createClient } from '@/app/lib/supabase/server-client'; +import { StoreInsert } from '@/app/types/store'; + +// create store +export const createStore = async (data: StoreInsert) => { + const supabase = await createClient(); + const { data: entry, error: err } = await supabase + .from('stores') + .insert(data) + .select() + .single(); + + if (err) { + console.error('Error creating store:', err); + return { success: false, error: err }; + } + return { success: true, data: entry }; +}; + +// delete store given store_id +export const deleteStore = async (storeId: string) => { + const supabase = await createClient(); + const { error: err } = await supabase + .from('stores') + .delete() + .eq('store_id', storeId); + + if (err) { + console.error('Error deleting store:', err); + return { success: false, error: err }; + } + return { success: true }; +}; diff --git a/app/api/ticket-items/actions.ts b/app/api/ticket-items/actions.ts new file mode 100644 index 0000000..4404e09 --- /dev/null +++ b/app/api/ticket-items/actions.ts @@ -0,0 +1,68 @@ +'use server'; + +import { TicketItemInsert } from '@/app/types/ticket'; +import { createClient } from '@/app/lib/supabase/server-client'; + +export async function createTicketItem(data: TicketItemInsert) { + const supabase = await createClient(); + // Server Action uses a mutation method + const { data: entry, error: err } = await supabase + .from('ticket_items') + .insert(data) + .select() + .single(); + + if (err) { + console.error('Error creating ticket item:', err); + return { success: false, error: err }; + } + return { success: true, data: entry }; +} + +export async function changeTicketItemQuantity( + ticketItemId: string, + newQuantity: number, +) { + const supabase = await createClient(); + const { error: err } = await supabase + .from('ticket_items') + .update({ quantity_requested: newQuantity }) + .eq('ticket_item_id', ticketItemId); + + if (err) { + console.error('Error changing ticket item quantity:', err); + return { success: false, error: err }; + } + return { success: true }; +} + +export async function changeTicketItemDescription( + ticketItemId: string, + newDescription: string, +) { + const supabase = await createClient(); + const { error: err } = await supabase + .from('ticket_items') + .update({ free_text_description: newDescription }) + .eq('ticket_item_id', ticketItemId); + + if (err) { + console.error('Error changing ticket item description:', err); + return { success: false, error: err }; + } + return { success: true }; +} + +export async function deleteTicketItem(ticketItemId: string) { + const supabase = await createClient(); + const { error: err } = await supabase + .from('ticket_items') + .delete() + .eq('ticket_item_id', ticketItemId); + + if (err) { + console.error('Error deleting ticket item:', err); + return { success: false, error: err }; + } + return { success: true }; +} diff --git a/app/api/tickets/actions.ts b/app/api/tickets/actions.ts new file mode 100644 index 0000000..cdb96f8 --- /dev/null +++ b/app/api/tickets/actions.ts @@ -0,0 +1,48 @@ +'use server'; // directive that indicates that the functions we define are server actions + +import { TicketInsert } from '@/app/types/ticket'; +import { createClient } from '@/app/lib/supabase/server-client'; + +export async function createTicket(data: TicketInsert) { + const supabase = await createClient(); + // pulling out the error from the insert into tickets table + const { data: entry, error: err } = await supabase + .from('tickets') + .insert(data) + .select() + .single(); + + if (err) { + console.error('Error creating ticket:', err); + return { success: false, error: err }; + } + return { success: true, data: entry }; +} + +export async function deleteTicket(ticketId: string) { + const supabase = await createClient(); + const { error: err } = await supabase + .from('tickets') + .delete() + .eq('ticket_id', ticketId); + + if (err) { + console.error('Error deleting ticket:', err); + return { success: false, error: err }; + } + return { success: true }; +} + +export async function updateTicketStatus(newStatus: string, ticketId: string) { + const supabase = await createClient(); + const { error: err } = await supabase + .from('tickets') + .update({ status: newStatus }) + .eq('ticket_id', ticketId); + + if (err) { + console.error('Error changing ticket status:', err); + return { success: false, error: err }; + } + return { success: true }; +} diff --git a/app/components/test/DonationsTestComponent.tsx b/app/components/test/DonationsTestComponent.tsx new file mode 100644 index 0000000..97577a3 --- /dev/null +++ b/app/components/test/DonationsTestComponent.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { createDonation, deleteDonation } from '@/app/api/donations/actions'; + +export default function DonationsTestComponent() { + const handleCreate = async () => { + try { + const donation = await createDonation({ + receiver_user_id: '00000000-0000-0000-0000-000000000000', + store_id: null, + donor_is_individual: true, + donor_individual_name: 'Test User', + donor_business_name: 'Donor Business Name', + donor_business_contact_name: 'Ms. Donor', + donor_email: 'test@example.com', + donor_phone: '123-456-7890', + donor_street_address: '1234 Bruin Ave', + donor_receive_mailings: false, + donor_receive_emails: true, + donor_remain_anonymous: false, + estimated_value: 50, + items_donated: 'Items donated!', + }); + + console.log('Created donation:', donation); + } catch (err) { + console.error('Create failed:', err); + } + }; + + const handleDelete = async () => { + const idToDelete = '40b188ab-e9a1-444d-9e6b-6b99d5017c90'; // hard-coded ID for now + try { + const result = await deleteDonation(idToDelete); + console.log('Deleted donation:', result); + } catch (err) { + console.error('Delete failed:', err); + } + }; + + return ( +
+

Test Donations

+ + +
+ ); +} diff --git a/app/components/test/ExampleTestComponent.tsx b/app/components/test/ExampleTestComponent.tsx new file mode 100644 index 0000000..0831c41 --- /dev/null +++ b/app/components/test/ExampleTestComponent.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { createExampleEntry } from '@/app/api/example/actions'; +import { Example } from '@/app/types/example'; + +export default function ExampleTestComponent() { + const data: Example = { + id: 5, + name: 'harry', + }; + + const handleExampleClick = async () => { + await createExampleEntry(data); + }; + + return ( + + ); +} diff --git a/app/components/test/InventoryItemsTestComponent.tsx b/app/components/test/InventoryItemsTestComponent.tsx new file mode 100644 index 0000000..9cc69ad --- /dev/null +++ b/app/components/test/InventoryItemsTestComponent.tsx @@ -0,0 +1,90 @@ +'use client'; + +import { useState } from 'react'; +import type { InventoryItemInsert } from '@/app/types/inventory'; +import { + createItem, + changeItemQuantity, + deleteItem, +} from '@/app/api/inventory-items/actions'; + +export default function InventoryItemsTestComponent() { + const [inventoryId, setInventoryId] = useState(''); + const [inventoryIdToDelete, setInventoryIdToDelete] = useState(''); + const [updatedQuantity, setUpdatedQuantity] = useState(0); + + const data: InventoryItemInsert = { + store_id: '4c7b2b65-16df-44b5-a3c2-e2fcd090b76c', + subcategory_id: 1, + item: 'Sample Item', + description: 'test description', + photo_url: 'http://example.com/photo.jpg', + quantity_available: 2, + is_hidden: false, + }; + + const handleCreateItem = async () => { + await createItem(data); + }; + + const handleChangeItemQuantity = async () => { + await changeItemQuantity(inventoryId, Number(updatedQuantity)); + }; + + const handleDeleteItem = async () => { + await deleteItem(inventoryIdToDelete); + }; + + return ( +
+
+

Create an Item

+ +
+
+

Update an Item

+
+ +
+ +
+ +
+
+

Delete an Item

+
+ +
+ +
+
+
+ ); +} diff --git a/app/components/test/StoresTestComponent.tsx b/app/components/test/StoresTestComponent.tsx new file mode 100644 index 0000000..a971406 --- /dev/null +++ b/app/components/test/StoresTestComponent.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { createStore, deleteStore } from '@/app/api/stores/actions'; +import { StoreInsert } from '@/app/types/store'; + +export default function StoresTestComponent() { + const storeData: StoreInsert = { + name: 'test store', + street_address: 'test address', + }; + + const handleAddStoreClick = async () => { + await createStore(storeData); + }; + + const handleDeleteStoreClick = async () => { + await deleteStore('ea9a0fac-c881-4740-894c-34139859a057'); + }; + + return ( +
+ + +
+ ); +} diff --git a/app/components/test/TicketItemsTestComponent.tsx b/app/components/test/TicketItemsTestComponent.tsx new file mode 100644 index 0000000..fe7929a --- /dev/null +++ b/app/components/test/TicketItemsTestComponent.tsx @@ -0,0 +1,48 @@ +'use client'; + +import { + createTicketItem, + changeTicketItemDescription, + changeTicketItemQuantity, + deleteTicketItem, +} from '@/app/api/ticket-items/actions'; +import { TicketItemInsert } from '@/app/types/ticket'; + +export default function TicketItemTestComponent() { + const data: TicketItemInsert = { + ticket_id: 'c088b0b7-e4c3-40ae-80ca-9d8376dbb4fa', + inventory_item_id: 'bec1fdd9-d6f0-4c49-aa2f-c67a18fc05f2', + free_text_description: 'sample description', + quantity_requested: 10, + is_in_stock_request: true, + }; + + const ticketItemId = '4a3e0f98-e17a-4891-9d7c-d72f44245adc'; + + const handleCreate = async () => { + await createTicketItem(data); + }; + + const handleDelete = async () => { + await deleteTicketItem(ticketItemId); + }; + + const handleChangeDescription = async () => { + await changeTicketItemDescription(ticketItemId, 'new description'); + }; + + const handleChangeQuantity = async () => { + await changeTicketItemQuantity(ticketItemId, 5); + }; + + return ( +
+ + + + +
+ ); +} diff --git a/app/components/test/TicketsTestComponent.tsx b/app/components/test/TicketsTestComponent.tsx new file mode 100644 index 0000000..e4cb22d --- /dev/null +++ b/app/components/test/TicketsTestComponent.tsx @@ -0,0 +1,83 @@ +'use client'; + +import { + createTicket, + deleteTicket, + updateTicketStatus, +} from '@/app/api/tickets/actions'; +import { useState } from 'react'; +import { TicketInsert } from '@/app/types/ticket'; + +export default function TicketsTestComponent() { + const [ticketToDelete, setDelete] = useState(''); + const [ticketToUpdate, setUpdateTicket] = useState(''); + const [updateStatus, setStatus] = useState(''); + + const ticketData: TicketInsert = { + requestor_user_id: '4c4f3502-1b31-4040-8a7a-2baedbc8a347', + store_id: '94b6329f-7383-46e2-978d-e105d31c3813', + status: 'ready', + }; + + const submitTicket = async () => { + await createTicket(ticketData); + }; + + const sendTicketDeletion = async () => { + await deleteTicket(ticketToDelete); + }; + + const updateTicket = async () => { + await updateTicketStatus(updateStatus, ticketToUpdate); + }; + + return ( +
+

Ticket Testing

+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +} diff --git a/app/globals.css b/app/globals.css index dd085e1..581442c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,4 +1,4 @@ -@import "tailwindcss"; +@import 'tailwindcss'; :root { --background: #ffffff; diff --git a/app/layout.tsx b/app/layout.tsx index 735d2b7..7095646 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,9 +1,9 @@ -import type { Metadata } from "next"; -import "./globals.css"; +import type { Metadata } from 'next'; +import './globals.css'; export const metadata: Metadata = { - title: "PATH App", - description: "Resource management application for PATH", + title: 'PATH App', + description: 'Resource management application for PATH', }; export default function RootLayout({ @@ -13,9 +13,7 @@ export default function RootLayout({ }>) { return ( - - {children} - + {children} ); } diff --git a/app/lib/supabase/browser-client.ts b/app/lib/supabase/browser-client.ts index 063c38d..7aab535 100644 --- a/app/lib/supabase/browser-client.ts +++ b/app/lib/supabase/browser-client.ts @@ -1,8 +1,8 @@ -import { createBrowserClient } from "@supabase/ssr"; +import { createBrowserClient } from '@supabase/ssr'; export function createClient() { return createBrowserClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, ); -} \ No newline at end of file +} diff --git a/app/lib/supabase/server-client.ts b/app/lib/supabase/server-client.ts index 2d239fa..421518b 100644 --- a/app/lib/supabase/server-client.ts +++ b/app/lib/supabase/server-client.ts @@ -1,5 +1,5 @@ -import { createServerClient } from "@supabase/ssr"; -import { cookies } from "next/headers"; +import { createServerClient } from '@supabase/ssr'; +import { cookies } from 'next/headers'; export async function createClient() { const cookieStore = await cookies(); return createServerClient( @@ -13,13 +13,13 @@ export async function createClient() { setAll(cookiesToSet) { try { cookiesToSet.forEach(({ name, value, options }) => - cookieStore.set(name, value, options) + cookieStore.set(name, value, options), ); } catch { - throw new Error("Cookies are not available"); + throw new Error('Cookies are not available'); } }, }, - } + }, ); -} \ No newline at end of file +} diff --git a/app/page.tsx b/app/page.tsx index 1d25e78..050e73b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,14 +1,14 @@ -"use client"; +'use client'; -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; +import { useEffect } from 'react'; +import { useRouter } from 'next/navigation'; export default function Home() { const router = useRouter(); useEffect(() => { // replace() avoids adding to browser history - router.replace("/example"); + router.replace('/test'); }, [router]); return null; -} \ No newline at end of file +} diff --git a/app/types/donation.ts b/app/types/donation.ts new file mode 100644 index 0000000..8909d9e --- /dev/null +++ b/app/types/donation.ts @@ -0,0 +1,25 @@ +export type Donation = { + donation_id: string; // generated by database + receiver_user_id: string; + store_id?: string | null; + + date_submitted: Date | string; // generated by default + donor_is_individual: boolean; + + donor_individual_name?: string | null; // optional + donor_business_name?: string | null; // optional + donor_business_contact_name?: string | null; // optional + + donor_email: string; + donor_phone?: string | null; // optional + + donor_street_address?: string | null; // optional + donor_receive_mailings: boolean; + donor_receive_emails: boolean; + donor_remain_anonymous: boolean; + + estimated_value: number; + items_donated: string; +}; + +export type DonationInsert = Omit; diff --git a/app/types/ExampleType.ts b/app/types/example.ts similarity index 50% rename from app/types/ExampleType.ts rename to app/types/example.ts index 42ecc61..3e3a313 100644 --- a/app/types/ExampleType.ts +++ b/app/types/example.ts @@ -1,4 +1,4 @@ -export type ExampleType = { +export type Example = { id: number; name: string; -}; \ No newline at end of file +}; diff --git a/app/types/inventory.ts b/app/types/inventory.ts new file mode 100644 index 0000000..adf17ad --- /dev/null +++ b/app/types/inventory.ts @@ -0,0 +1,14 @@ +export type InventoryItem = { + inventory_item_id: string; // UUID + store_id: string; // UUID + subcategory_id: number; + item: string; + description: string; + photo_url?: string | null; + quantity_available: number; + is_hidden: boolean; +}; + +export type InventoryItemUpdate = Partial; + +export type InventoryItemInsert = Omit; diff --git a/app/types/store.ts b/app/types/store.ts new file mode 100644 index 0000000..0e2abcb --- /dev/null +++ b/app/types/store.ts @@ -0,0 +1,7 @@ +export type Store = { + store_id: string; + name: string; + street_address: string; +}; + +export type StoreInsert = Omit; diff --git a/app/types/ticket.ts b/app/types/ticket.ts new file mode 100644 index 0000000..92f5b7c --- /dev/null +++ b/app/types/ticket.ts @@ -0,0 +1,24 @@ +export type Ticket = { + ticket_id: string; // string corresponds to uuid + requestor_user_id: string; + store_id: string; + status: string; // string corresponds to varchar + date_submitted: Date | string; // Date | string corresponds to time stamp with time zone +}; + +export type TicketUpdate = Partial; + +export type TicketInsert = Omit; + +export type TicketItem = { + ticket_item_id: string; + ticket_id: string; + inventory_item_id?: string | null; + free_text_description?: string | null; + quantity_requested?: number | null; + is_in_stock_request: boolean; +}; + +export type TicketItemUpdate = Partial; + +export type TicketItemInsert = Omit; diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..386b0bc 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,17 +1,19 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; +import { defineConfig, globalIgnores } from 'eslint/config'; +import nextVitals from 'eslint-config-next/core-web-vitals'; +import nextTs from 'eslint-config-next/typescript'; +import prettier from 'eslint-config-prettier/flat'; const eslintConfig = defineConfig([ ...nextVitals, ...nextTs, + prettier, // Override default ignores of eslint-config-next. globalIgnores([ // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', ]), ]); diff --git a/next.config.ts b/next.config.ts index e9ffa30..5e891cf 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,4 +1,4 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ diff --git a/package-lock.json b/package-lock.json index a7a5582..54b511a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@supabase/ssr": "^0.7.0", "@supabase/supabase-js": "^2.81.1", - "next": "16.0.1", + "next": "^16.0.7", "react": "19.2.0", "react-dom": "19.2.0" }, @@ -21,6 +21,9 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.0.1", + "eslint-config-prettier": "^10.1.8", + "prettier": "^3.7.4", + "prettier-plugin-sql": "^0.19.2", "supabase": "^2.58.5", "tailwindcss": "^4", "typescript": "^5" @@ -1051,9 +1054,9 @@ } }, "node_modules/@next/env": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.1.tgz", - "integrity": "sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", + "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1067,9 +1070,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.1.tgz", - "integrity": "sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.10.tgz", + "integrity": "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==", "cpu": [ "arm64" ], @@ -1083,9 +1086,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz", - "integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz", + "integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==", "cpu": [ "x64" ], @@ -1099,9 +1102,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz", - "integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz", + "integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==", "cpu": [ "arm64" ], @@ -1115,9 +1118,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz", - "integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz", + "integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==", "cpu": [ "arm64" ], @@ -1131,9 +1134,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz", - "integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz", + "integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==", "cpu": [ "x64" ], @@ -1147,9 +1150,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz", - "integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz", + "integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==", "cpu": [ "x64" ], @@ -1163,9 +1166,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz", - "integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz", + "integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==", "cpu": [ "arm64" ], @@ -1179,9 +1182,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz", - "integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz", + "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==", "cpu": [ "x64" ], @@ -1661,6 +1664,13 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/pegjs": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@types/pegjs/-/pegjs-0.10.6.tgz", + "integrity": "sha512-eLYXDbZWXh2uxf+w8sXS8d6KSoXTswfps6fvCUuVAGN8eRpfe7h9eSRydxiSJvo9Bf+GzifsDOr9TMQlmJdmkw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/phoenix": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", @@ -2579,6 +2589,16 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, "node_modules/bin-links": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-6.0.0.tgz", @@ -2797,6 +2817,13 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2984,6 +3011,13 @@ "node": ">=8" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "dev": true, + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -3340,6 +3374,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -4685,9 +4735,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -4744,6 +4794,16 @@ "node": ">=6" } }, + "node_modules/jsox": { + "version": "1.2.124", + "resolved": "https://registry.npmjs.org/jsox/-/jsox-1.2.124.tgz", + "integrity": "sha512-KwptI8xUfOt7qJ+P+2utrJIEHTgDjXpBsDhPSM4GDq++4by+LX9nUFee97QfRloGcMh5iA9Ha/4UCVZl7zWzuA==", + "dev": true, + "license": "MIT", + "bin": { + "jsox": "lib/cli.js" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -5201,6 +5261,13 @@ "node": ">= 18" } }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5249,13 +5316,36 @@ "dev": true, "license": "MIT" }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, "node_modules/next": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz", - "integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/next/-/next-16.0.10.tgz", + "integrity": "sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==", "license": "MIT", "dependencies": { - "@next/env": "16.0.1", + "@next/env": "16.0.10", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -5268,14 +5358,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.1", - "@next/swc-darwin-x64": "16.0.1", - "@next/swc-linux-arm64-gnu": "16.0.1", - "@next/swc-linux-arm64-musl": "16.0.1", - "@next/swc-linux-x64-gnu": "16.0.1", - "@next/swc-linux-x64-musl": "16.0.1", - "@next/swc-win32-arm64-msvc": "16.0.1", - "@next/swc-win32-x64-msvc": "16.0.1", + "@next/swc-darwin-arm64": "16.0.10", + "@next/swc-darwin-x64": "16.0.10", + "@next/swc-linux-arm64-gnu": "16.0.10", + "@next/swc-linux-arm64-musl": "16.0.10", + "@next/swc-linux-x64-gnu": "16.0.10", + "@next/swc-linux-x64-musl": "16.0.10", + "@next/swc-win32-arm64-msvc": "16.0.10", + "@next/swc-win32-x64-msvc": "16.0.10", "sharp": "^0.34.4" }, "peerDependencies": { @@ -5376,6 +5466,20 @@ "dev": true, "license": "MIT" }, + "node_modules/node-sql-parser": { + "version": "5.3.13", + "resolved": "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-5.3.13.tgz", + "integrity": "sha512-heyWv3lLjKHpcBDMUSR+R0DohRYZTYq+Ro3hJ4m9Ia8ccdKbL5UijIaWr2L4co+bmmFuvBVZ4v23QW2PqvBFAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/pegjs": "^0.10.0", + "big-integer": "^1.6.48" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm-normalize-package-bin": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", @@ -5685,6 +5789,44 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-sql": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.19.2.tgz", + "integrity": "sha512-DAu1Jcanpvs32OAOXsqaVXOpPs4nFLVkB3XwzRiZZVNL5/c+XdlNxWFMiMpMhYhmCG5BW3srK8mhikCOv5tPfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsox": "^1.2.123", + "node-sql-parser": "^5.3.10", + "sql-formatter": "^15.6.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + }, + "peerDependencies": { + "prettier": "^3.0.3" + } + }, "node_modules/proc-log": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", @@ -5738,6 +5880,27 @@ ], "license": "MIT" }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/react": { "version": "19.2.0", "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", @@ -5861,6 +6024,16 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6195,6 +6368,20 @@ "node": ">=0.10.0" } }, + "node_modules/sql-formatter": { + "version": "15.6.11", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.11.tgz", + "integrity": "sha512-T2aqOqwpGNqDvKNLJqsIVPhEgDCEp795GeXZg7AqbDTHmaEDBBAy/rwBd8lxnlYEjFm/DI+AsD7dnmJNhlUSWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "nearley": "^2.20.1" + }, + "bin": { + "sql-formatter": "bin/sql-formatter-cli.cjs" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -6376,9 +6563,9 @@ } }, "node_modules/supabase": { - "version": "2.58.5", - "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.58.5.tgz", - "integrity": "sha512-mYZSkUIePTdmwlHd26Pff8wpmjfre8gcuWzrc5QqhZgZvCXugVzAQQhcjaQisw5kusbPQWNIjUwcHYEKmejhPw==", + "version": "2.61.2", + "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.61.2.tgz", + "integrity": "sha512-dSmCHErwEQrpSQb1PKzpwZqhEl8qj8KVzVtqJBcKROmPOeWZ9CAghxW5uX2B1bGKPjVXAN6MA4rP/Mr7+qmj1A==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index 8b899b9..6622171 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,14 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "format:check": "prettier --check .", + "format:fix": "prettier --write ." }, "dependencies": { "@supabase/ssr": "^0.7.0", "@supabase/supabase-js": "^2.81.1", - "next": "16.0.1", + "next": "^16.0.7", "react": "19.2.0", "react-dom": "19.2.0" }, @@ -22,6 +24,9 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.0.1", + "eslint-config-prettier": "^10.1.8", + "prettier": "^3.7.4", + "prettier-plugin-sql": "^0.19.2", "supabase": "^2.58.5", "tailwindcss": "^4", "typescript": "^5" diff --git a/supabase/migrations/20251125060428_create_stores_table.sql b/supabase/migrations/20251125060428_create_stores_table.sql new file mode 100644 index 0000000..33595ec --- /dev/null +++ b/supabase/migrations/20251125060428_create_stores_table.sql @@ -0,0 +1,90 @@ + + create table "public"."stores" ( + "store_id" text, + "name" text, + "street_address" text + ); + + +alter table "public"."stores" enable row level security; + +grant delete on table "public"."stores" to "anon"; + +grant insert on table "public"."stores" to "anon"; + +grant references on table "public"."stores" to "anon"; + +grant select on table "public"."stores" to "anon"; + +grant trigger on table "public"."stores" to "anon"; + +grant truncate on table "public"."stores" to "anon"; + +grant update on table "public"."stores" to "anon"; + +grant delete on table "public"."stores" to "authenticated"; + +grant insert on table "public"."stores" to "authenticated"; + +grant references on table "public"."stores" to "authenticated"; + +grant select on table "public"."stores" to "authenticated"; + +grant trigger on table "public"."stores" to "authenticated"; + +grant truncate on table "public"."stores" to "authenticated"; + +grant update on table "public"."stores" to "authenticated"; + +grant delete on table "public"."stores" to "service_role"; + +grant insert on table "public"."stores" to "service_role"; + +grant references on table "public"."stores" to "service_role"; + +grant select on table "public"."stores" to "service_role"; + +grant trigger on table "public"."stores" to "service_role"; + +grant truncate on table "public"."stores" to "service_role"; + +grant update on table "public"."stores" to "service_role"; + + + create policy "public can delete entries in stores" + on "public"."stores" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert entries in stores" + on "public"."stores" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can read entries in stores" + on "public"."stores" + as permissive + for select + to anon +using (true); + + + + create policy "public can update entries in stores" + on "public"."stores" + as permissive + for update + to anon +using (true) +with check (true); + + + diff --git a/supabase/migrations/20251125063314_create_donations_table.sql b/supabase/migrations/20251125063314_create_donations_table.sql new file mode 100644 index 0000000..27f39be --- /dev/null +++ b/supabase/migrations/20251125063314_create_donations_table.sql @@ -0,0 +1,106 @@ + + create table "public"."donations" ( + "donation_id" text not null default (gen_random_uuid())::text, + "receiver_user_id" text not null, + "store_id" text, + "date_submitted" timestamp with time zone default CURRENT_TIMESTAMP, + "donor_is_individual" boolean not null, + "donor_individual_name" text, + "donor_business_name" text, + "donor_business_contact_name" text, + "donor_email" character varying(255), + "donor_phone" character varying(20), + "donor_street_address" boolean not null, + "donor_receive_mailings" boolean not null, + "donor_receive_emails" boolean not null, + "donor_remain_anonymous" boolean not null, + "estimated_value" numeric not null, + "items_donated" text not null + ); + + +alter table "public"."donations" enable row level security; + +CREATE UNIQUE INDEX donations_pkey ON public.donations USING btree (donation_id); + +alter table "public"."donations" add constraint "donations_pkey" PRIMARY KEY using index "donations_pkey"; + +grant delete on table "public"."donations" to "anon"; + +grant insert on table "public"."donations" to "anon"; + +grant references on table "public"."donations" to "anon"; + +grant select on table "public"."donations" to "anon"; + +grant trigger on table "public"."donations" to "anon"; + +grant truncate on table "public"."donations" to "anon"; + +grant update on table "public"."donations" to "anon"; + +grant delete on table "public"."donations" to "authenticated"; + +grant insert on table "public"."donations" to "authenticated"; + +grant references on table "public"."donations" to "authenticated"; + +grant select on table "public"."donations" to "authenticated"; + +grant trigger on table "public"."donations" to "authenticated"; + +grant truncate on table "public"."donations" to "authenticated"; + +grant update on table "public"."donations" to "authenticated"; + +grant delete on table "public"."donations" to "service_role"; + +grant insert on table "public"."donations" to "service_role"; + +grant references on table "public"."donations" to "service_role"; + +grant select on table "public"."donations" to "service_role"; + +grant trigger on table "public"."donations" to "service_role"; + +grant truncate on table "public"."donations" to "service_role"; + +grant update on table "public"."donations" to "service_role"; + + + create policy "public can delete entries in donations" + on "public"."donations" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert entries in donations" + on "public"."donations" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can read entries in donations" + on "public"."donations" + as permissive + for select + to anon +using (true); + + + + create policy "public can update entries in donations" + on "public"."donations" + as permissive + for update + to anon +with check (true); + + + diff --git a/supabase/migrations/20251201081622_create_ticket_items.sql b/supabase/migrations/20251201081622_create_ticket_items.sql new file mode 100644 index 0000000..16fed36 --- /dev/null +++ b/supabase/migrations/20251201081622_create_ticket_items.sql @@ -0,0 +1,93 @@ + + create table "public"."ticket_items" ( + "ticket_item_id" uuid default extensions.uuid_generate_v4(), + "ticket_id" uuid not null, + "inventory_item_id" uuid, + "free_text_description" text, + "quantity_requested" integer, + "is_in_stock_request" boolean not null + ); + + +alter table "public"."ticket_items" enable row level security; + +grant delete on table "public"."ticket_items" to "anon"; + +grant insert on table "public"."ticket_items" to "anon"; + +grant references on table "public"."ticket_items" to "anon"; + +grant select on table "public"."ticket_items" to "anon"; + +grant trigger on table "public"."ticket_items" to "anon"; + +grant truncate on table "public"."ticket_items" to "anon"; + +grant update on table "public"."ticket_items" to "anon"; + +grant delete on table "public"."ticket_items" to "authenticated"; + +grant insert on table "public"."ticket_items" to "authenticated"; + +grant references on table "public"."ticket_items" to "authenticated"; + +grant select on table "public"."ticket_items" to "authenticated"; + +grant trigger on table "public"."ticket_items" to "authenticated"; + +grant truncate on table "public"."ticket_items" to "authenticated"; + +grant update on table "public"."ticket_items" to "authenticated"; + +grant delete on table "public"."ticket_items" to "service_role"; + +grant insert on table "public"."ticket_items" to "service_role"; + +grant references on table "public"."ticket_items" to "service_role"; + +grant select on table "public"."ticket_items" to "service_role"; + +grant trigger on table "public"."ticket_items" to "service_role"; + +grant truncate on table "public"."ticket_items" to "service_role"; + +grant update on table "public"."ticket_items" to "service_role"; + + + create policy "public can delete tiecket_items" + on "public"."ticket_items" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert ticket_items" + on "public"."ticket_items" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can read ticket_items" + on "public"."ticket_items" + as permissive + for select + to anon +using (true); + + + + create policy "public can update ticket_items" + on "public"."ticket_items" + as permissive + for update + to anon +using (true) +with check (true); + + + diff --git a/supabase/migrations/20251202055330_remote_schema.sql b/supabase/migrations/20251202055330_remote_schema.sql new file mode 100644 index 0000000..375c089 --- /dev/null +++ b/supabase/migrations/20251202055330_remote_schema.sql @@ -0,0 +1,57 @@ +drop policy "public can delete entries in donations" on "public"."donations"; + +drop policy "public can insert entries in donations" on "public"."donations"; + +drop policy "public can read entries in donations" on "public"."donations"; + +drop policy "public can update entries in donations" on "public"."donations"; + +revoke delete on table "public"."donations" from "anon"; + +revoke insert on table "public"."donations" from "anon"; + +revoke references on table "public"."donations" from "anon"; + +revoke select on table "public"."donations" from "anon"; + +revoke trigger on table "public"."donations" from "anon"; + +revoke truncate on table "public"."donations" from "anon"; + +revoke update on table "public"."donations" from "anon"; + +revoke delete on table "public"."donations" from "authenticated"; + +revoke insert on table "public"."donations" from "authenticated"; + +revoke references on table "public"."donations" from "authenticated"; + +revoke select on table "public"."donations" from "authenticated"; + +revoke trigger on table "public"."donations" from "authenticated"; + +revoke truncate on table "public"."donations" from "authenticated"; + +revoke update on table "public"."donations" from "authenticated"; + +revoke delete on table "public"."donations" from "service_role"; + +revoke insert on table "public"."donations" from "service_role"; + +revoke references on table "public"."donations" from "service_role"; + +revoke select on table "public"."donations" from "service_role"; + +revoke trigger on table "public"."donations" from "service_role"; + +revoke truncate on table "public"."donations" from "service_role"; + +revoke update on table "public"."donations" from "service_role"; + +alter table "public"."donations" drop constraint "donations_pkey"; + +drop index if exists "public"."donations_pkey"; + +drop table "public"."donations"; + + diff --git a/supabase/migrations/20251202064747_fix_donations_type.sql b/supabase/migrations/20251202064747_fix_donations_type.sql new file mode 100644 index 0000000..31012e3 --- /dev/null +++ b/supabase/migrations/20251202064747_fix_donations_type.sql @@ -0,0 +1,106 @@ + + create table "public"."donations" ( + "donation_id" uuid not null default extensions.uuid_generate_v4(), + "receiver_user_id" uuid not null, + "store_id" uuid, + "date_submitted" timestamp with time zone default CURRENT_TIMESTAMP, + "donor_is_individual" boolean not null, + "donor_individual_name" text, + "donor_business_name" text, + "donor_business_contact_name" text, + "donor_email" character varying(255), + "donor_phone" character varying(20), + "donor_street_address" text, + "donor_receive_mailings" boolean not null, + "donor_receive_emails" boolean not null, + "donor_remain_anonymous" boolean not null, + "estimated_value" numeric not null, + "items_donated" text not null + ); + + +alter table "public"."donations" enable row level security; + +CREATE UNIQUE INDEX donations_pkey ON public.donations USING btree (donation_id); + +alter table "public"."donations" add constraint "donations_pkey" PRIMARY KEY using index "donations_pkey"; + +grant delete on table "public"."donations" to "anon"; + +grant insert on table "public"."donations" to "anon"; + +grant references on table "public"."donations" to "anon"; + +grant select on table "public"."donations" to "anon"; + +grant trigger on table "public"."donations" to "anon"; + +grant truncate on table "public"."donations" to "anon"; + +grant update on table "public"."donations" to "anon"; + +grant delete on table "public"."donations" to "authenticated"; + +grant insert on table "public"."donations" to "authenticated"; + +grant references on table "public"."donations" to "authenticated"; + +grant select on table "public"."donations" to "authenticated"; + +grant trigger on table "public"."donations" to "authenticated"; + +grant truncate on table "public"."donations" to "authenticated"; + +grant update on table "public"."donations" to "authenticated"; + +grant delete on table "public"."donations" to "service_role"; + +grant insert on table "public"."donations" to "service_role"; + +grant references on table "public"."donations" to "service_role"; + +grant select on table "public"."donations" to "service_role"; + +grant trigger on table "public"."donations" to "service_role"; + +grant truncate on table "public"."donations" to "service_role"; + +grant update on table "public"."donations" to "service_role"; + + + create policy "public can delete entries in donations" + on "public"."donations" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert entries in donations" + on "public"."donations" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can read entries in donations" + on "public"."donations" + as permissive + for select + to anon +using (true); + + + + create policy "public can update entries in donations" + on "public"."donations" + as permissive + for update + to anon +with check (true); + + + diff --git a/supabase/migrations/20251205044154_update_stores_table.sql b/supabase/migrations/20251205044154_update_stores_table.sql new file mode 100644 index 0000000..03082f4 --- /dev/null +++ b/supabase/migrations/20251205044154_update_stores_table.sql @@ -0,0 +1,11 @@ +alter table "public"."stores" alter column "store_id" set default extensions.uuid_generate_v4(); + +alter table "public"."stores" alter column "store_id" set not null; + +alter table "public"."stores" alter column "store_id" set data type uuid using "store_id"::uuid; + +CREATE UNIQUE INDEX stores_pkey ON public.stores USING btree (store_id); + +alter table "public"."stores" add constraint "stores_pkey" PRIMARY KEY using index "stores_pkey"; + + diff --git a/supabase/migrations/20251205055058_add_primary_key.sql b/supabase/migrations/20251205055058_add_primary_key.sql new file mode 100644 index 0000000..0dfa520 --- /dev/null +++ b/supabase/migrations/20251205055058_add_primary_key.sql @@ -0,0 +1,7 @@ +alter table "public"."ticket_items" alter column "ticket_item_id" set not null; + +CREATE UNIQUE INDEX ticket_items_pkey ON public.ticket_items USING btree (ticket_item_id); + +alter table "public"."ticket_items" add constraint "ticket_items_pkey" PRIMARY KEY using index "ticket_items_pkey"; + + diff --git a/supabase/migrations/20251205055906_inventory_items.sql b/supabase/migrations/20251205055906_inventory_items.sql new file mode 100644 index 0000000..ec2e284 --- /dev/null +++ b/supabase/migrations/20251205055906_inventory_items.sql @@ -0,0 +1,99 @@ + + create table "public"."inventory_items" ( + "inventory_item_id" uuid not null default extensions.uuid_generate_v4(), + "store_id" uuid not null, + "subcategory" integer not null, + "item" character varying(255) not null, + "description" text not null, + "photo_url" text, + "quantity_available" integer not null, + "is_hidden" boolean not null + ); + + +alter table "public"."inventory_items" enable row level security; + +CREATE UNIQUE INDEX inventory_items_pkey ON public.inventory_items USING btree (inventory_item_id); + +alter table "public"."inventory_items" add constraint "inventory_items_pkey" PRIMARY KEY using index "inventory_items_pkey"; + +grant delete on table "public"."inventory_items" to "anon"; + +grant insert on table "public"."inventory_items" to "anon"; + +grant references on table "public"."inventory_items" to "anon"; + +grant select on table "public"."inventory_items" to "anon"; + +grant trigger on table "public"."inventory_items" to "anon"; + +grant truncate on table "public"."inventory_items" to "anon"; + +grant update on table "public"."inventory_items" to "anon"; + +grant delete on table "public"."inventory_items" to "authenticated"; + +grant insert on table "public"."inventory_items" to "authenticated"; + +grant references on table "public"."inventory_items" to "authenticated"; + +grant select on table "public"."inventory_items" to "authenticated"; + +grant trigger on table "public"."inventory_items" to "authenticated"; + +grant truncate on table "public"."inventory_items" to "authenticated"; + +grant update on table "public"."inventory_items" to "authenticated"; + +grant delete on table "public"."inventory_items" to "service_role"; + +grant insert on table "public"."inventory_items" to "service_role"; + +grant references on table "public"."inventory_items" to "service_role"; + +grant select on table "public"."inventory_items" to "service_role"; + +grant trigger on table "public"."inventory_items" to "service_role"; + +grant truncate on table "public"."inventory_items" to "service_role"; + +grant update on table "public"."inventory_items" to "service_role"; + + + create policy "public can delete entries in inventory_items" + on "public"."inventory_items" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert entries in inventory_items" + on "public"."inventory_items" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can select entries in inventory_items" + on "public"."inventory_items" + as permissive + for select + to anon +using (true); + + + + create policy "public can update entries in inventory_items" + on "public"."inventory_items" + as permissive + for update + to anon +using (true) +with check (true); + + + diff --git a/supabase/migrations/20251205060123_fix_typo.sql b/supabase/migrations/20251205060123_fix_typo.sql new file mode 100644 index 0000000..2e4070f --- /dev/null +++ b/supabase/migrations/20251205060123_fix_typo.sql @@ -0,0 +1,12 @@ +drop policy "public can delete tiecket_items" on "public"."ticket_items"; + + + create policy "public can delete ticket_items" + on "public"."ticket_items" + as permissive + for delete + to anon +using (true); + + + diff --git a/supabase/migrations/20251205063407_add_ticket_status_enum.sql b/supabase/migrations/20251205063407_add_ticket_status_enum.sql new file mode 100644 index 0000000..3c4ac0b --- /dev/null +++ b/supabase/migrations/20251205063407_add_ticket_status_enum.sql @@ -0,0 +1,98 @@ +create type "public"."ticket_status" as enum ('requested', 'ready', 'rejected', 'fulfilled'); + + + create table "public"."tickets" ( + "ticket_id" uuid not null default extensions.uuid_generate_v4(), + "requestor_user_id" uuid not null, + "store_id" uuid not null, + "status" public.ticket_status not null, + "date_submitted" timestamp with time zone default now() + ); + + +alter table "public"."tickets" enable row level security; + +CREATE UNIQUE INDEX tickets_pkey ON public.tickets USING btree (ticket_id); + +alter table "public"."tickets" add constraint "tickets_pkey" PRIMARY KEY using index "tickets_pkey"; + +grant delete on table "public"."tickets" to "anon"; + +grant insert on table "public"."tickets" to "anon"; + +grant references on table "public"."tickets" to "anon"; + +grant select on table "public"."tickets" to "anon"; + +grant trigger on table "public"."tickets" to "anon"; + +grant truncate on table "public"."tickets" to "anon"; + +grant update on table "public"."tickets" to "anon"; + +grant delete on table "public"."tickets" to "authenticated"; + +grant insert on table "public"."tickets" to "authenticated"; + +grant references on table "public"."tickets" to "authenticated"; + +grant select on table "public"."tickets" to "authenticated"; + +grant trigger on table "public"."tickets" to "authenticated"; + +grant truncate on table "public"."tickets" to "authenticated"; + +grant update on table "public"."tickets" to "authenticated"; + +grant delete on table "public"."tickets" to "service_role"; + +grant insert on table "public"."tickets" to "service_role"; + +grant references on table "public"."tickets" to "service_role"; + +grant select on table "public"."tickets" to "service_role"; + +grant trigger on table "public"."tickets" to "service_role"; + +grant truncate on table "public"."tickets" to "service_role"; + +grant update on table "public"."tickets" to "service_role"; + + + create policy "public can delete entries in tickets" + on "public"."tickets" + as permissive + for delete + to anon +using (true); + + + + create policy "public can insert entries in tickets" + on "public"."tickets" + as permissive + for insert + to anon +with check (true); + + + + create policy "public can read entries in tickets" + on "public"."tickets" + as permissive + for select + to anon +using (true); + + + + create policy "public can update entries in tickets" + on "public"."tickets" + as permissive + for update + to anon +using (true) +with check (true); + + + diff --git a/supabase/migrations/20251218042006_minor_table_edits.sql b/supabase/migrations/20251218042006_minor_table_edits.sql new file mode 100644 index 0000000..79aca1f --- /dev/null +++ b/supabase/migrations/20251218042006_minor_table_edits.sql @@ -0,0 +1,11 @@ +alter table "public"."donations" alter column "donor_email" set not null; + +alter table "public"."inventory_items" drop column "subcategory"; + +alter table "public"."inventory_items" add column "subcategory_id" integer not null; + +alter table "public"."stores" alter column "name" set not null; + +alter table "public"."stores" alter column "street_address" set not null; + + diff --git a/supabase/schemas/donations.sql b/supabase/schemas/donations.sql new file mode 100644 index 0000000..b3f9916 --- /dev/null +++ b/supabase/schemas/donations.sql @@ -0,0 +1,49 @@ +/* +- Create the donations table according to schema described +- Write RLS (row level security) policies following supabase/schemas/example.sql +that enable unauthenticated users to view/update the table +*/ +create table donations ( + donation_id uuid default uuid_generate_v4 () primary key, -- generated by default + receiver_user_id uuid not null, -- references users(id), -- linked to users table, required + store_id uuid, -- references stores(id), -- linked to stores table, optional + date_submitted timestamp with time zone default current_timestamp, -- generated by default + donor_is_individual boolean not null, -- required, used if donor is an individual + donor_individual_name text, -- optional, used if donor is an individual + donor_business_name text, -- optional, used if donor is a business + donor_business_contact_name text, -- optional, used if donor is a business + donor_email varchar(255) not null, -- can't store more than 255 characters + donor_phone varchar(20), -- optional, can't store more than 20 characters + donor_street_address text, -- optional, street address + donor_receive_mailings boolean not null, -- required, whether or not donor wants to receive mailings + donor_receive_emails boolean not null, -- required, whether or not donor wants to receive emails + donor_remain_anonymous boolean not null, -- required, whether or not donor wants to remain anonymous + estimated_value numeric not null, -- required, estimated value of donation in USD + items_donated text not null -- required, free-text description of items +); + +-- write RLS policies that enable select, insert, update, and delete across all unauthenticated users +alter table donations enable row level security; + +-- select +create policy "public can read entries in donations" on public.donations for +select + to anon -- applies to anon role (anonymous/public users) + using (true); + +-- all rows satisfy condition, all rows are readable +-- insert +create policy "public can insert entries in donations" on public.donations for insert to anon -- applies to anon role (anonymous/public users) +with + check (true); + +-- for insert/update row validation, only rows where condition evaluates to true can be inserted/updated +-- update +create policy "public can update entries in donations" on public.donations +for update + to anon +with + check (true); + +-- delete +create policy "public can delete entries in donations" on public.donations for delete to anon using (true); diff --git a/supabase/schemas/example.sql b/supabase/schemas/example.sql index ee8272c..01d7190 100644 --- a/supabase/schemas/example.sql +++ b/supabase/schemas/example.sql @@ -1,16 +1,11 @@ -create table "example" ( - "id" integer not null, - "name" text -); +create table "example" ("id" integer not null, "name" text); alter table example enable row level security; -create policy "public can read example" -on public.example -for select to anon -using (true); +create policy "public can read example" on public.example for +select + to anon using (true); -create policy "public can insert entries in example" -on public.example -for insert to anon -with check (true); \ No newline at end of file +create policy "public can insert entries in example" on public.example for insert to anon +with + check (true); diff --git a/supabase/schemas/inventory_items.sql b/supabase/schemas/inventory_items.sql new file mode 100644 index 0000000..577a71a --- /dev/null +++ b/supabase/schemas/inventory_items.sql @@ -0,0 +1,28 @@ +create table "inventory_items" ( + "inventory_item_id" uuid primary key default uuid_generate_v4 (), + "store_id" uuid not null, + "subcategory_id" int not null, + "item" varchar(255) not null, + "description" text not null, + "photo_url" text, + "quantity_available" int not null, + "is_hidden" boolean not null +); + +alter table "inventory_items" enable row level security; + +create policy "public can select entries in inventory_items" on public.inventory_items for +select + to anon using (true); + +create policy "public can insert entries in inventory_items" on public.inventory_items for insert to anon +with + check (true); + +create policy "public can update entries in inventory_items" on public.inventory_items +for update + to anon using (true) +with + check (true); + +create policy "public can delete entries in inventory_items" on public.inventory_items for delete to anon using (true); diff --git a/supabase/schemas/stores.sql b/supabase/schemas/stores.sql new file mode 100644 index 0000000..5dae477 --- /dev/null +++ b/supabase/schemas/stores.sql @@ -0,0 +1,23 @@ +create table "stores" ( + store_id uuid default uuid_generate_v4 () primary key, + name text not null, + street_address text not null +); + +alter table "stores" enable row level security; + +create policy "public can read entries in stores" on public.stores for +select + to anon using (true); + +create policy "public can insert entries in stores" on public.stores for insert to anon +with + check (true); + +create policy "public can update entries in stores" on public.stores +for update + to anon using (true) +with + check (true); + +create policy "public can delete entries in stores" on public.stores for delete to anon using (true); diff --git a/supabase/schemas/ticket_items.sql b/supabase/schemas/ticket_items.sql new file mode 100644 index 0000000..2857d30 --- /dev/null +++ b/supabase/schemas/ticket_items.sql @@ -0,0 +1,32 @@ +create table ticket_items ( + ticket_item_id uuid default uuid_generate_v4 () primary key, + ticket_id uuid not null, + inventory_item_id uuid, + free_text_description text, + quantity_requested int, + is_in_stock_request boolean not null + /* CONSTRAINT fk_tickets + FOREIGN KEY ticket_id + REFERENCES tickets(ticket_id) + CONSTRAINT fk_inventory_items + FOREIGN KEY inventory_item_id + REFERENCES inventory_items(inventory_item_id)*/ +); + +alter table "ticket_items" enable row level security; + +create policy "public can read ticket_items" on public.ticket_items for +select + to anon using (true); + +create policy "public can insert ticket_items" on public.ticket_items for insert to anon +with + check (true); + +create policy "public can update ticket_items" on public.ticket_items +for update + to anon using (true) +with + check (true); + +create policy "public can delete ticket_items" on public.ticket_items for delete to anon using (true); diff --git a/supabase/schemas/tickets.sql b/supabase/schemas/tickets.sql new file mode 100644 index 0000000..7d5f427 --- /dev/null +++ b/supabase/schemas/tickets.sql @@ -0,0 +1,29 @@ +create type ticket_status as enum('requested', 'ready', 'rejected', 'fulfilled'); + +create table "tickets" ( + "ticket_id" uuid default uuid_generate_v4 () primary key, + "requestor_user_id" uuid not null, + "store_id" uuid not null, + "status" ticket_status not null, -- max 50 character status + "date_submitted" timestamp with time zone default now() + -- FOREIGN KEY (requestor_user_id) REFERENCES users(user_id), + -- FOREIGN KEY (store_id) REFERENCES stores(store_id) +); + +alter table tickets enable row level security; + +create policy "public can read entries in tickets" on public.tickets for +select + to anon using (true); + +create policy "public can insert entries in tickets" on public.tickets for insert to anon +with + check (true); + +create policy "public can update entries in tickets" on public.tickets +for update + to anon using (true) +with + check (true); + +create policy "public can delete entries in tickets" on public.tickets for delete to anon using (true); diff --git a/supabase/seeds/example.sql b/supabase/seeds/example.sql index 16af5b8..f8b4f51 100644 --- a/supabase/seeds/example.sql +++ b/supabase/seeds/example.sql @@ -1,5 +1,5 @@ -insert into example - (id, name) +insert into + example (id, name) values (1, 'alice'), - (2, 'bob'); \ No newline at end of file + (2, 'bob');