From 5816bfc3d69abb4993b725c327b940a2c5ab23c5 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 25 Feb 2026 22:01:15 -0500 Subject: [PATCH 1/3] feat: allow beep with null beeper --- .../migration.sql | 1 + .../snapshot.json | 1685 +++++++++++++++++ api/drizzle/relations.ts | 2 +- api/drizzle/schema.ts | 1 - api/src/routers/rider.ts | 137 +- api/src/schemas/beep.ts | 2 +- app/app/(app)/(drawer)/index.tsx | 49 +- 7 files changed, 1812 insertions(+), 65 deletions(-) create mode 100644 api/drizzle/20260226025302_medical_king_bedlam/migration.sql create mode 100644 api/drizzle/20260226025302_medical_king_bedlam/snapshot.json diff --git a/api/drizzle/20260226025302_medical_king_bedlam/migration.sql b/api/drizzle/20260226025302_medical_king_bedlam/migration.sql new file mode 100644 index 00000000..4f369c2f --- /dev/null +++ b/api/drizzle/20260226025302_medical_king_bedlam/migration.sql @@ -0,0 +1 @@ +ALTER TABLE "beep" ALTER COLUMN "beeper_id" DROP NOT NULL; \ No newline at end of file diff --git a/api/drizzle/20260226025302_medical_king_bedlam/snapshot.json b/api/drizzle/20260226025302_medical_king_bedlam/snapshot.json new file mode 100644 index 00000000..c29e0895 --- /dev/null +++ b/api/drizzle/20260226025302_medical_king_bedlam/snapshot.json @@ -0,0 +1,1685 @@ +{ + "version": "8", + "dialect": "postgres", + "id": "e1034aaf-9976-4087-91b3-7d97b341545a", + "prevIds": [ + "9b17fd7b-d6ec-4d5b-bb51-7bb621d0f0aa" + ], + "ddl": [ + { + "values": [ + "canceled", + "denied", + "waiting", + "accepted", + "on_the_way", + "here", + "in_progress", + "complete" + ], + "name": "beep_status", + "entityType": "enums", + "schema": "public" + }, + { + "values": [ + "top_of_beeper_list_1_hour", + "top_of_beeper_list_2_hours", + "top_of_beeper_list_3_hours" + ], + "name": "payment_product", + "entityType": "enums", + "schema": "public" + }, + { + "values": [ + "play_store", + "app_store" + ], + "name": "payment_store", + "entityType": "enums", + "schema": "public" + }, + { + "values": [ + "sha256", + "bcrypt" + ], + "name": "user_password_type", + "entityType": "enums", + "schema": "public" + }, + { + "values": [ + "user", + "admin" + ], + "name": "user_role", + "entityType": "enums", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "beep", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "car", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "feedback", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "forgot_password", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "payment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "rating", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "report", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "user", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "verify_email", + "entityType": "tables", + "schema": "public" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "beeper_id", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rider_id", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "origin", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "destination", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "group_size", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "beep_status", + "typeSchema": "public", + "notNull": true, + "dimensions": 0, + "default": "'waiting'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "beep" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "make", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "color", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "photo", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "year", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "default", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated", + "entityType": "columns", + "schema": "public", + "table": "car" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "feedback" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "feedback" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message", + "entityType": "columns", + "schema": "public", + "table": "feedback" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created", + "entityType": "columns", + "schema": "public", + "table": "feedback" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "forgot_password" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "forgot_password" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "time", + "entityType": "columns", + "schema": "public", + "table": "forgot_password" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "store_id", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "payment_product", + "typeSchema": "public", + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "product_id", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "numeric", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "price", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "payment_store", + "typeSchema": "public", + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "store", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires", + "entityType": "columns", + "schema": "public", + "table": "payment" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rater_id", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rated_id", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "stars", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "timestamp", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "beep_id", + "entityType": "columns", + "schema": "public", + "table": "rating" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reporter_id", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reported_id", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "handled_by_id", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reason", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "notes", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "timestamp", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "handled", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "beep_id", + "entityType": "columns", + "schema": "public", + "table": "report" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "token" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tokenid", + "entityType": "columns", + "schema": "public", + "table": "token" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "token" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "first", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "username", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "phone", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "venmo", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cashapp", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "password", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "user_password_type", + "typeSchema": "public", + "notNull": true, + "dimensions": 0, + "default": "'bcrypt'", + "generated": null, + "identity": null, + "name": "password_type", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "is_beeping", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "is_email_verified", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "is_student", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "4", + "generated": null, + "identity": null, + "name": "group_rate", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "3", + "generated": null, + "identity": null, + "name": "singles_rate", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "4", + "generated": null, + "identity": null, + "name": "capacity", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "queue_size", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "numeric", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rating", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "user_role", + "typeSchema": "public", + "notNull": true, + "dimensions": 0, + "default": "'user'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "push_token", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "photo", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "geometry", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "location", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "verify_email" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "verify_email" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "time", + "entityType": "columns", + "schema": "public", + "table": "verify_email" + }, + { + "type": "varchar(255)", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "verify_email" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "beeper_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "beeper_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "beeper_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "rider_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "beeper_id_rider_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "rider_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "rider_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "start", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "start_idx", + "entityType": "indexes", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "status", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "status_idx", + "entityType": "indexes", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "is_beeping", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "is_beeping_idx", + "entityType": "indexes", + "schema": "public", + "table": "user" + }, + { + "nameExplicit": false, + "columns": [ + "beeper_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "beep_beeper_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": false, + "columns": [ + "rider_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "beep_rider_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "beep" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "car_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "car" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "feedback_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "feedback" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "forgot_password_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "forgot_password" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "payment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "payment" + }, + { + "nameExplicit": false, + "columns": [ + "rater_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "rating_rater_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "rating" + }, + { + "nameExplicit": false, + "columns": [ + "rated_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "rating_rated_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "rating" + }, + { + "nameExplicit": false, + "columns": [ + "beep_id" + ], + "schemaTo": "public", + "tableTo": "beep", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "rating_beep_id_beep_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "rating" + }, + { + "nameExplicit": false, + "columns": [ + "reporter_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "report_reporter_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "report" + }, + { + "nameExplicit": false, + "columns": [ + "reported_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "report_reported_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "report" + }, + { + "nameExplicit": false, + "columns": [ + "handled_by_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "SET NULL", + "name": "report_handled_by_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "report" + }, + { + "nameExplicit": false, + "columns": [ + "beep_id" + ], + "schemaTo": "public", + "tableTo": "beep", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "SET NULL", + "name": "report_beep_id_beep_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "report" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "token_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "token" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "CASCADE", + "onDelete": "CASCADE", + "name": "verify_email_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "verify_email" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "beep_pkey", + "schema": "public", + "table": "beep", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "car_pkey", + "schema": "public", + "table": "car", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "feedback_pkey", + "schema": "public", + "table": "feedback", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "forgot_password_pkey", + "schema": "public", + "table": "forgot_password", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "payment_pkey", + "schema": "public", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "rating_pkey", + "schema": "public", + "table": "rating", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "report_pkey", + "schema": "public", + "table": "report", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "token_pkey", + "schema": "public", + "table": "token", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_pkey", + "schema": "public", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "verify_email_pkey", + "schema": "public", + "table": "verify_email", + "entityType": "pks" + }, + { + "nameExplicit": true, + "columns": [ + "rater_id", + "beep_id" + ], + "nullsNotDistinct": false, + "name": "rating_beep_id_rater_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "rating" + }, + { + "nameExplicit": true, + "columns": [ + "username" + ], + "nullsNotDistinct": false, + "name": "user_username_unique", + "entityType": "uniques", + "schema": "public", + "table": "user" + }, + { + "nameExplicit": true, + "columns": [ + "email" + ], + "nullsNotDistinct": false, + "name": "user_email_unique", + "entityType": "uniques", + "schema": "public", + "table": "user" + } + ], + "renames": [] +} \ No newline at end of file diff --git a/api/drizzle/relations.ts b/api/drizzle/relations.ts index 5efc1666..03fe5670 100644 --- a/api/drizzle/relations.ts +++ b/api/drizzle/relations.ts @@ -118,7 +118,7 @@ export const relations = defineRelations( from: r.beep.beeper_id, to: r.user.id, alias: "beeper", - optional: false, + optional: true, }), rider: r.one.user({ from: r.beep.rider_id, diff --git a/api/drizzle/schema.ts b/api/drizzle/schema.ts index ecf7bae0..9b2d10c6 100644 --- a/api/drizzle/schema.ts +++ b/api/drizzle/schema.ts @@ -173,7 +173,6 @@ export const beep = pgTable( { id: varchar("id", { length: 255 }).primaryKey().notNull(), beeper_id: varchar("beeper_id", { length: 255 }) - .notNull() .references(() => user.id, { onUpdate: "cascade", onDelete: "cascade" }), rider_id: varchar("rider_id", { length: 255 }) .notNull() diff --git a/api/src/routers/rider.ts b/api/src/routers/rider.ts index 49694e74..bf65afaa 100644 --- a/api/src/routers/rider.ts +++ b/api/src/routers/rider.ts @@ -91,7 +91,7 @@ export const riderRouter = router({ .use(withLock) .input( z.object({ - beeperId: z.string(), + beeperId: z.string().optional(), origin: z.string(), destination: z.string(), groupSize: z.number().min(1).max(25), @@ -117,35 +117,94 @@ export const riderRouter = router({ }); } - const beeper = await db.query.user.findFirst({ - where: { id: input.beeperId }, + const currentRide = await db.query.beep.findFirst({ + where: { AND: [{ rider_id: ctx.user.id }, inProgressBeepNew] } }); - const queue = await getBeeperQueue(input.beeperId); - - if (!beeper) { + if (currentRide) { throw new TRPCError({ - code: "NOT_FOUND", - message: "Beeper not found", + code: "BAD_REQUEST", + message: "You are already in an active beep. You can't start another beep until your current one is done." }); } - if (!beeper.isBeeping) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "That user is not beeping. Maybe they stopped beeping.", + if (input.beeperId) { + const beeper = await db.query.user.findFirst({ + where: { id: input.beeperId }, }); - } - if (queue.some((beep) => beep.rider_id === ctx.user.id)) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "You are already in that beeper's queue.", + const queue = await getBeeperQueue(input.beeperId); + + if (!beeper) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Beeper not found", + }); + } + + if (!beeper.isBeeping) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "That user is not beeping. Maybe they stopped beeping.", + }); + } + + if (queue.some((beep) => beep.rider_id === ctx.user.id)) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "You are already in that beeper's queue.", + }); + } + + + const newBeep = { + beeper_id: beeper.id, + rider_id: ctx.user.id, + destination: input.destination, + origin: input.origin, + groupSize: input.groupSize, + id: crypto.randomUUID(), + start: new Date(), + status: "waiting", + end: null, + } as const; + + + await db.insert(beep).values(newBeep); + + queue.push({ + ...newBeep, + rider: ctx.user, + beeper, }); + + pubSub.publish("queue", beeper.id, { queue }); + + for (const beep of queue) { + pubSub.publish("ride", beep.rider_id, { + ride: { ...beep, ...getDerivedRiderFields(beep, queue) }, + }); + } + + if (beeper.pushToken) { + sendNotification({ + to: beeper.pushToken, + title: `${ctx.user.first} ${ctx.user.last} has entered your queue 🚕`, + body: "Please accept or deny this rider.", + categoryId: "newbeep", + data: { id: newBeep.id }, + }); + } + + return { + ...newBeep, + ...getDerivedRiderFields(newBeep, queue), + beeper, + }; } const newBeep = { - beeper_id: beeper.id, + beeper_id: null, rider_id: ctx.user.id, destination: input.destination, origin: input.origin, @@ -156,48 +215,14 @@ export const riderRouter = router({ end: null, } as const; - const currentRide = await db.query.beep.findFirst({ - where: { AND: [{ rider_id: ctx.user.id }, inProgressBeepNew] } - }); - - if (currentRide) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "You are already in an active beep. You can't start another beep until your current one is done." - }); - } await db.insert(beep).values(newBeep); - queue.push({ - ...newBeep, - rider: ctx.user, - beeper, - }); - - pubSub.publish("queue", beeper.id, { queue }); + const ride = { ...beep, ...getDerivedRiderFields(newBeep, []), beeper: null }; - for (const beep of queue) { - pubSub.publish("ride", beep.rider_id, { - ride: { ...beep, ...getDerivedRiderFields(beep, queue) }, - }); - } + pubSub.publish("ride", ctx.user.id, { ride }); - if (beeper.pushToken) { - sendNotification({ - to: beeper.pushToken, - title: `${ctx.user.first} ${ctx.user.last} has entered your queue 🚕`, - body: "Please accept or deny this rider.", - categoryId: "newbeep", - data: { id: newBeep.id }, - }); - } - - return { - ...newBeep, - ...getDerivedRiderFields(newBeep, queue), - beeper, - }; + return ride; }), currentRide: authedProcedure .input(z.string().optional()) @@ -206,7 +231,7 @@ export const riderRouter = router({ const userId = input ?? ctx.user.id; if (ctx.user.role === 'user' && userId !== ctx.user.id) { - throw new TRPCError({ code: "FORBIDDEN", message: "You must be an admin to view the current ride of another user"}); + throw new TRPCError({ code: "FORBIDDEN", message: "You must be an admin to view the current ride of another user" }); } return getRidersCurrentRide(userId); diff --git a/api/src/schemas/beep.ts b/api/src/schemas/beep.ts index baa43f2a..3492ee19 100644 --- a/api/src/schemas/beep.ts +++ b/api/src/schemas/beep.ts @@ -18,7 +18,7 @@ export const rideResponseSchema = z.object({ groupRate: z.number(), singlesRate: z.number(), photo: z.string().nullable(), - }), + }).nullable(), position: z.number(), queue: z.array(z.object({ status: z.enum(beepStatuses) })), riders_waiting: z.number() diff --git a/app/app/(app)/(drawer)/index.tsx b/app/app/(app)/(drawer)/index.tsx index 54cbcf54..88dd99b1 100644 --- a/app/app/(app)/(drawer)/index.tsx +++ b/app/app/(app)/(drawer)/index.tsx @@ -1,15 +1,15 @@ import React, { useEffect } from "react"; import { useTRPC } from "@/utils/trpc"; -import { skipToken, useQuery } from "@tanstack/react-query"; +import { skipToken, useMutation, useQuery } from "@tanstack/react-query"; import { useSubscription } from "@trpc/tanstack-react-query"; import { useQueryClient } from "@tanstack/react-query"; import { RideDetails } from "../../../components/RideDetails"; import { BottomSheet } from "@/components/BottomSheet"; -import { View } from "react-native"; +import { Switch, View } from "react-native"; import { RideMap } from "../../../components/RideMap"; import { BottomSheetView } from "@gorhom/bottom-sheet"; import { SplashScreen, useLocalSearchParams, useRouter } from "expo-router"; -import { Controller, useForm } from "react-hook-form"; +import { Controller, useForm, useWatch } from "react-hook-form"; import { KeyboardAwareScrollView } from "react-native-keyboard-controller"; import { Label } from "@/components/Label"; import { Text } from "@/components/Text"; @@ -18,10 +18,12 @@ import { LocationInput } from "@/components/LocationInput"; import { Button } from "@/components/Button"; import { BeepersMap } from "@/components/BeepersMap"; import { RateLastBeeper } from "@/components/RateLastBeeper"; +import { useLocation } from "@/utils/location"; export default function MainFindBeepScreen() { const trpc = useTRPC(); const queryClient = useQueryClient(); + const { getLocation } = useLocation(false); const { data: beep } = useQuery(trpc.rider.currentRide.queryOptions()); @@ -69,17 +71,42 @@ export default function MainFindBeepScreen() { control, handleSubmit, setFocus, + watch, formState: { errors }, } = useForm({ values: { groupSize: params.groupSize ? String(params.groupSize) : "", origin: params.origin ?? "", destination: params.destination ?? "", + chooseBeeper: true, }, }); - const findBeep = handleSubmit((values) => { - router.navigate({ pathname: '/ride/pick', params: values }); + const { mutate: startBeep, isPending } = useMutation( + trpc.rider.startBeep.mutationOptions({ + onSuccess(data) { + queryClient.setQueryData(trpc.rider.currentRide.queryKey(), data); + }, + onError(error) { + alert(error.message); + }, + }), + ); + + const chooseBeeper = watch('chooseBeeper'); + + const findBeep = handleSubmit(async ({ chooseBeeper, ...values }) => { + if (chooseBeeper) { + router.navigate({ pathname: '/ride/pick', params: values }); + } else { + const location = await getLocation(); + + startBeep({ + ...values, + groupSize: Number(values.groupSize), + ...location.coords, + }); + } }); if (!beep) { @@ -158,7 +185,17 @@ export default function MainFindBeepScreen() { /> {errors.destination?.message} - + + Choose a beeper + ( + + )} + /> + + From a5f191ecfd3ad4f0c180015d6b04a92ca0b82050 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 25 Feb 2026 22:47:26 -0500 Subject: [PATCH 2/3] more progress --- api/src/logic/beep.ts | 2 +- api/src/routers/rider.ts | 103 ++++++++++++----------- app/app/(app)/(drawer)/index.tsx | 2 +- app/components/Beep.tsx | 4 +- app/components/RideDetails.tsx | 30 ++++++- app/components/RideMenu.tsx | 24 +++--- website/src/components/BasicUser.tsx | 13 ++- website/src/components/TableCellUser.tsx | 13 ++- website/src/routes/admin/beeps/Beep.tsx | 2 +- 9 files changed, 127 insertions(+), 66 deletions(-) diff --git a/api/src/logic/beep.ts b/api/src/logic/beep.ts index aa0b2991..2d0d7e2b 100644 --- a/api/src/logic/beep.ts +++ b/api/src/logic/beep.ts @@ -83,7 +83,7 @@ export async function getRidersCurrentRide(userId: string) { return null; } - const queue = await getBeeperQueue(beep.beeper_id) + const queue = beep.beeper_id ? await getBeeperQueue(beep.beeper_id) : []; return { ...beep, ...getDerivedRiderFields(beep, queue) }; } diff --git a/api/src/routers/rider.ts b/api/src/routers/rider.ts index bf65afaa..3e17eb4a 100644 --- a/api/src/routers/rider.ts +++ b/api/src/routers/rider.ts @@ -218,7 +218,7 @@ export const riderRouter = router({ await db.insert(beep).values(newBeep); - const ride = { ...beep, ...getDerivedRiderFields(newBeep, []), beeper: null }; + const ride = { ...newBeep, ...getDerivedRiderFields(newBeep, []), beeper: null }; pubSub.publish("ride", ctx.user.id, { ride }); @@ -379,69 +379,78 @@ export const riderRouter = router({ } }), leaveQueue: authedProcedure - .input( - z.object({ - beeperId: z.string(), - }), - ) .mutation(async ({ ctx, input }) => { - const beeper = await db.query.user.findFirst({ - where: { id: input.beeperId }, + const ride = await db.query.beep.findFirst({ + where: { AND: [{ rider_id: ctx.user.id }, inProgressBeepNew] }, }); - if (!beeper) { + if (!ride) { throw new TRPCError({ code: "NOT_FOUND", - message: "Beeper not found.", + message: "You are not in a beep.", }); } - let queue = await getBeeperQueue(input.beeperId); + if (ride.beeper_id) { - if (!beeper) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Beeper not found.", - }); - } + let queue = await getBeeperQueue(ride.beeper_id); - const entry = queue.find((beep) => beep.rider.id === ctx.user.id); + const beeper = await db.query.user.findFirst({ + where: { id: ride.beeper_id } + }) - if (!entry) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "You are not in that beepers queue.", - }); - } + if (!beeper) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Beeper not found.", + }); + } - if (beeper.pushToken) { - sendNotification({ - to: beeper.pushToken, - title: `${ctx.user.first} ${ctx.user.last} left your queue 🥹`, - body: "They decided they did not want a beep from you!", - }); - } + const entry = queue.find((beep) => beep.rider.id === ctx.user.id); + + if (!entry) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "You are not in that beepers queue.", + }); + } + + if (beeper.pushToken) { + sendNotification({ + to: beeper.pushToken, + title: `${ctx.user.first} ${ctx.user.last} left your queue 🥹`, + body: "They decided they did not want a beep from you!", + }); + } - await db - .update(beep) - .set({ status: "canceled", end: new Date() }) - .where(eq(beep.id, entry.id)); + await db + .update(beep) + .set({ status: "canceled", end: new Date() }) + .where(eq(beep.id, entry.id)); - queue = queue.filter((beep) => beep.id !== entry.id); + queue = queue.filter((beep) => beep.id !== entry.id); - pubSub.publish("ride", ctx.user.id, { ride: null }); - pubSub.publish("queue", beeper.id, { queue }); + pubSub.publish("ride", ctx.user.id, { ride: null }); + pubSub.publish("queue", beeper.id, { queue }); - for (const beep of queue) { - pubSub.publish("ride", beep.rider_id, { - ride: { ...beep, ...getDerivedRiderFields(beep, queue) }, - }); - } + for (const beep of queue) { + pubSub.publish("ride", beep.rider_id, { + ride: { ...beep, ...getDerivedRiderFields(beep, queue) }, + }); + } - await db - .update(user) - .set({ queueSize: getQueueSize(queue) }) - .where(eq(user.id, beeper.id)); + await db + .update(user) + .set({ queueSize: getQueueSize(queue) }) + .where(eq(user.id, beeper.id)); + } else { + await db + .update(beep) + .set({ status: "canceled", end: new Date() }) + .where(eq(beep.id, ride.id)); + + pubSub.publish("ride", ctx.user.id, { ride: null }); + } return true; }), diff --git a/app/app/(app)/(drawer)/index.tsx b/app/app/(app)/(drawer)/index.tsx index 88dd99b1..ca5f3880 100644 --- a/app/app/(app)/(drawer)/index.tsx +++ b/app/app/(app)/(drawer)/index.tsx @@ -49,7 +49,7 @@ export default function MainFindBeepScreen() { const { data: beepersLocation } = useSubscription( trpc.rider.beeperLocationUpdates.subscriptionOptions( - beep ? beep.beeper.id : skipToken, + beep?.beeper ? beep.beeper.id : skipToken, { enabled: isAcceptedBeep, }, diff --git a/app/components/Beep.tsx b/app/components/Beep.tsx index 3b849186..2fb95b48 100644 --- a/app/components/Beep.tsx +++ b/app/components/Beep.tsx @@ -26,11 +26,11 @@ export function Beep({ item }: Props) { const otherUser = user?.id === item.rider.id ? item.beeper : item.rider; const isRider = user?.id === item.rider.id; - const isBeeper = user?.id === item.beeper.id; + const isBeeper = item.beeper !== null && user?.id === item.beeper.id; const myRating = item.ratings.find((r) => r.rater_id === user?.id); const otherUsersRating = item.ratings.find( - (r) => r.rater_id === otherUser.id, + (r) => otherUser && r.rater_id === otherUser.id, ); const isAcceptedOrComplete = diff --git a/app/components/RideDetails.tsx b/app/components/RideDetails.tsx index 401bc810..d3fb4bad 100644 --- a/app/components/RideDetails.tsx +++ b/app/components/RideDetails.tsx @@ -33,7 +33,7 @@ export function RideDetails(props: Props) { const { data: car } = useQuery( trpc.user.getUsersDefaultCar.queryOptions( - beep ? beep.beeper.id : skipToken, + beep?.beeper ? beep.beeper.id : skipToken, { enabled: isAcceptedBeep }, ), ); @@ -42,6 +42,34 @@ export function RideDetails(props: Props) { return null; } + if (beep && !beep.beeper) { + return ( + + Waiting on a beeper to claim your ride request. + + Pick Up + {beep.origin} + + + Destination + {beep.destination} + + + Number of Riders + {beep.groupSize} + + + ); + } + return ( mutate({ beeperId: beep.beeper.id }), + onPress: () => mutate(), style: "destructive", }, ], { cancelable: true }, ); } else { - mutate({ beeperId: beep.beeper.id }); + mutate(); } }; @@ -83,12 +83,13 @@ export function RideMenu() { } options={[ + ...(beep.beeper ? [ { title: "Contact", show: beep.status !== "waiting", options: [ - { title: "Call", onClick: () => call(beep.beeper.id) }, - { title: "Text", onClick: () => sms(beep.beeper.id) }, + { title: "Call", onClick: () => call(beep.beeper!.id) }, + { title: "Text", onClick: () => sms(beep.beeper!.id) }, ], }, { @@ -100,10 +101,10 @@ export function RideMenu() { show: Boolean(beep.beeper.venmo), onClick: () => openVenmo( - beep.beeper.venmo, + beep.beeper!.venmo, beep.groupSize, - beep.beeper.groupRate, - beep.beeper.singlesRate, + beep.beeper!.groupRate, + beep.beeper!.singlesRate, "pay", ), }, @@ -112,14 +113,15 @@ export function RideMenu() { show: Boolean(beep.beeper.cashapp), onClick: () => openCashApp( - beep.beeper.cashapp, + beep.beeper!.cashapp, beep.groupSize, - beep.beeper.groupRate, - beep.beeper.singlesRate, + beep.beeper!.groupRate, + beep.beeper!.singlesRate, ), }, ], }, + ] : []), { title: "Cancel Ride", destructive: true, diff --git a/website/src/components/BasicUser.tsx b/website/src/components/BasicUser.tsx index 9eaf83f1..e6f58105 100644 --- a/website/src/components/BasicUser.tsx +++ b/website/src/components/BasicUser.tsx @@ -8,12 +8,23 @@ interface Props { photo: string | null | undefined; first: string; last: string; - }; + } | null; } export function BasicUser(props: Props) { const { user } = props; + if (!user) { + return ( + + + None + + + + ); + } + return ( diff --git a/website/src/components/TableCellUser.tsx b/website/src/components/TableCellUser.tsx index c20482b4..ddea8238 100644 --- a/website/src/components/TableCellUser.tsx +++ b/website/src/components/TableCellUser.tsx @@ -4,11 +4,22 @@ import { LinkProps } from '@tanstack/react-router'; import { Link } from './Link'; interface Props { - user: { first: string, last: string, id: string, photo: string | null }; + user: { first: string, last: string, id: string, photo: string | null } | null; linkProps?: Partial; } export function TableCellUser(props: Props) { + if (!props.user) { + return ( + + + + None + + + ); + } + return ( diff --git a/website/src/routes/admin/beeps/Beep.tsx b/website/src/routes/admin/beeps/Beep.tsx index 44bdfd9e..90794174 100644 --- a/website/src/routes/admin/beeps/Beep.tsx +++ b/website/src/routes/admin/beeps/Beep.tsx @@ -40,7 +40,7 @@ export function Beep() { } = useQuery(trpc.beep.beep.queryOptions(beepId)); const { data: beeper } = useSubscription( - trpc.user.updates.subscriptionOptions(beep ? beep.beeper_id : skipToken) + trpc.user.updates.subscriptionOptions(beep?.beeper ? beep.beeper.id : skipToken) ); const { data: route } = useQuery( From bbfb3f12b9720163caabf3beebcdc00d9782f69b Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 25 Feb 2026 22:49:40 -0500 Subject: [PATCH 3/3] fix: website typecheck --- website/src/routes/admin/users/Ride.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/routes/admin/users/Ride.tsx b/website/src/routes/admin/users/Ride.tsx index b89937b3..fe0808c7 100644 --- a/website/src/routes/admin/users/Ride.tsx +++ b/website/src/routes/admin/users/Ride.tsx @@ -34,7 +34,7 @@ export function Ride() { ); const { data: beeper } = useSubscription( - trpc.user.updates.subscriptionOptions(ride ? ride.beeper.id : skipToken) + trpc.user.updates.subscriptionOptions(ride?.beeper ? ride.beeper.id : skipToken) ); const { data: route } = useQuery(