+
+
+ Resource reviews
+
+
+ Proposed edits to existing PHLask resources and brand-new site
+ submissions, pending approval.
+
+
+
+
+
+ New site submissions
+
+
+
+
+
+
+ Edits to existing resources
+
+
+
+
);
};
diff --git a/app/types/ResourceEdit.ts b/app/types/ResourceEdit.ts
index 934482a..1b71b30 100644
--- a/app/types/ResourceEdit.ts
+++ b/app/types/ResourceEdit.ts
@@ -27,7 +27,32 @@ export type ResourceEdit = ResourceEntry & {
review_notes: string | null;
};
-/** A row from `resource_edits_queue`: a pending edit joined to its target resource. */
export type ResourceEditQueueRow = ResourceEdit & {
+ mapped_resource: number;
current_resource: ResourceEntry & { id: number };
};
+
+/**
+ * A row from `resource_edit_counts` — the number of PENDING edits currently
+ * queued against a given resource. Useful for flagging resources with
+ * multiple competing proposed edits before a reviewer picks one to approve.
+ */
+export type ResourceEditCount = {
+ resource_id: number;
+ pending_count: number;
+};
+
+/**
+ * A row from `resource_change_log` — a decided (APPROVED or REJECTED) edit,
+ * stripped down to just the review-lifecycle columns. One row per past
+ * decision, ordered by `resource_id` then most-recently-reviewed first.
+ */
+export type ResourceChangeLogEntry = {
+ edit_id: number;
+ resource_id: number | null;
+ review_status: EditReviewStatus;
+ submitted_by: string | null;
+ reviewed_by: string | null;
+ reviewed_at: string | null;
+ review_notes: string | null;
+};
diff --git a/app/types/ResourceEntry.ts b/app/types/ResourceEntry.ts
index f59f305..9584ca1 100644
--- a/app/types/ResourceEntry.ts
+++ b/app/types/ResourceEntry.ts
@@ -22,7 +22,8 @@ export type ResourceStatus =
| "OPERATIONAL"
| "TEMPORARILY_CLOSED"
| "PERMANENTLY_CLOSED"
- | "HIDDEN";
+ | "HIDDEN"
+ | "NONOPERATIONAL";
/**
* Entry permission type for a resource.
@@ -38,7 +39,7 @@ export type DispenserType =
| "SINK"
| "JUG"
| "SODA_MACHINE"
- | "PITCHER"
+ | "VESSEL"
| "WATER_COOLER";
/**
@@ -87,6 +88,7 @@ export type BathroomTag =
| "GENDER_NEUTRAL"
| "CHANGING_TABLE"
| "SINGLE_OCCUPANCY"
+ | "HAS_FOUNTAIN"
| "FAMILY";
/**
@@ -155,12 +157,17 @@ export type FoodInfo = {
food_type: FoodType[];
/** The permitted ways to access the food. Must have at least one entry. */
distribution_type: DistributionType[];
- /** The type of organization providing this food. Must have at least one entry. */
- organization_type: OrganizationType[];
+ /**
+ * The type of organization providing this food. A single value, matching
+ * phlask-map; rows predating its January 2026 schema change stored an array.
+ */
+ organization_type?: OrganizationType;
/** If available, the name of the organization providing the resource */
organization_name?: string;
/** If available, a URL to more information about this food resource */
organization_url?: string;
+ /** Free-form "helpful info" tags set by the phlask-map food form. Can be empty. */
+ tags?: string[];
};
/**
diff --git a/supabase/migrations/20260908120000_resource_edits_submitter_attribution.sql b/supabase/migrations/20260908120000_resource_edits_submitter_attribution.sql
new file mode 100644
index 0000000..a9eb571
--- /dev/null
+++ b/supabase/migrations/20260908120000_resource_edits_submitter_attribution.sql
@@ -0,0 +1,62 @@
+-- ============================================================================
+-- Populate `resource_edits.submitted_by` from the request's JWT.
+--
+-- Nothing was ever setting this column: submitting clients don't send it, and
+-- the admin dashboard only reads edits, never creates them. The result is that
+-- every row arrives with submitted_by = null, so the dashboard's "Top
+-- submitters" panel has nothing to attribute and the review detail page can't
+-- say who proposed a change.
+--
+-- `creator` is not a substitute — it's a mirrored ResourceEntry field carried
+-- along in the proposed snapshot, so it describes who created the *resource*
+-- (values are ingest sources like 'phlask_app'), not who submitted the edit.
+--
+-- This fills the column from the JWT on insert whenever the submitter is
+-- signed in, without requiring any client change. Anonymous submissions still
+-- land with submitted_by = null — there is genuinely no identity to record —
+-- so attributing those requires the submitting client to send something.
+-- ============================================================================
+
+begin;
+
+create or replace function public._resource_edits_set_submitter()
+returns trigger
+language plpgsql
+as $$
+declare
+ claims jsonb;
+begin
+ -- Only fill a blank; never overwrite a value the client sent deliberately.
+ if new.submitted_by is not null and new.submitted_by <> '' then
+ return new;
+ end if;
+
+ -- Unset (e.g. a direct psql insert) or unparseable claims are not an error
+ -- here; the column just stays null.
+ begin
+ claims := nullif(current_setting('request.jwt.claims', true), '')::jsonb;
+ exception when others then
+ claims := null;
+ end;
+
+ -- nullif per-claim, not around the coalesce: an empty-string `email` must
+ -- fall through to `sub` rather than swallowing it.
+ new.submitted_by := coalesce(
+ nullif(claims ->> 'email', ''),
+ nullif(claims ->> 'sub', '')
+ );
+
+ return new;
+end;
+$$;
+
+-- BEFORE INSERT so the value is stored on the row itself, and so a plain
+-- `insert` still returns the row (no RETURNING surprises for clients).
+drop trigger if exists resource_edits_set_submitter on public.resource_edits;
+
+create trigger resource_edits_set_submitter
+ before insert on public.resource_edits
+ for each row
+ execute function public._resource_edits_set_submitter();
+
+commit;
diff --git a/supabase/rollback/20260908120000_resource_edits_submitter_attribution.down.sql b/supabase/rollback/20260908120000_resource_edits_submitter_attribution.down.sql
new file mode 100644
index 0000000..0a48aef
--- /dev/null
+++ b/supabase/rollback/20260908120000_resource_edits_submitter_attribution.down.sql
@@ -0,0 +1,9 @@
+-- Rollback for 20260908120000_resource_edits_submitter_attribution.sql
+-- Leaves already-attributed rows alone; only stops new inserts being filled in.
+
+begin;
+
+drop trigger if exists resource_edits_set_submitter on public.resource_edits;
+drop function if exists public._resource_edits_set_submitter();
+
+commit;