Fixed delete workflow and added additional profile info

This commit is contained in:
Corey Blais
2026-05-20 17:12:15 -04:00
parent 5db30022eb
commit 0db90aab45
9 changed files with 403 additions and 248 deletions
+31 -1
View File
@@ -224,6 +224,9 @@ const birdSchema = z.object({
name: z.string().trim().min(1).max(120),
tagId: z.string().trim().max(80).optional().or(z.literal('')),
species: z.string().trim().min(1).max(120),
motivators: z.string().trim().max(1000).optional().or(z.literal('')),
demotivators: z.string().trim().max(1000).optional().or(z.literal('')),
favoriteSnack: z.string().trim().max(160).optional().or(z.literal('')),
gender: birdGenderSchema.optional(),
dateOfBirth: dateStringSchema.optional().or(z.literal('')),
gotchaDay: dateStringSchema.optional().or(z.literal('')),
@@ -474,6 +477,9 @@ const normalizeBird = (row: BirdRow) => ({
name: row.name,
tagId: normalizeBandId(row.tag_id),
species: row.species,
motivators: row.motivators,
demotivators: row.demotivators,
favoriteSnack: row.favorite_snack,
gender: row.gender,
dateOfBirth: row.date_of_birth,
gotchaDay: row.gotcha_day,
@@ -790,6 +796,21 @@ const syncWorkspaceStripeBilling = async (workspaceId: number) => {
);
};
const cancelWorkspaceStripeSubscription = async (workspace: WorkspaceRow) => {
if (workspace.workspace_type === 'rescue' || (!workspace.stripe_subscription_id && !workspace.stripe_customer_id)) {
return null;
}
const subscription = await getMostRelevantStripeSubscriptionForWorkspace(workspace);
if (!subscription || subscription.status === 'canceled') {
return null;
}
await getStripeClient().subscriptions.cancel(subscription.id);
return subscription.id;
};
const getStripePriceIdForBillingPlan = (billingPlan: BillingPlan, billingInterval: BillingInterval) => {
if (billingPlan === 'rescue_free') {
throw new Error('Rescue flocks do not use Stripe billing.');
@@ -2347,13 +2368,15 @@ app.delete('/api/workspace', requireAuth, requireSessionAuth, requireWorkspaceRo
return;
}
const canceledStripeSubscriptionId = await cancelWorkspaceStripeSubscription(req.auth!.workspace);
let nextWorkspaceId = await findAlternateWorkspaceForUser(req.auth!.user.id, req.auth!.workspace.id);
if (!nextWorkspaceId) {
const fallbackWorkspaceId = await getNextWorkspaceId();
const fallbackWorkspace = await createWorkspace({
id: fallbackWorkspaceId,
name: `${req.auth!.user.name}'s Flock`,
name: 'New Flock',
workspaceType: 'standard',
billingEmail: req.auth!.user.email,
billingPlan: 'household_basic',
@@ -2382,6 +2405,7 @@ app.delete('/api/workspace', requireAuth, requireSessionAuth, requireWorkspaceRo
res.json({
deletedWorkspaceId: req.auth!.workspace.id,
canceledStripeSubscriptionId,
token: req.auth!.token,
session: await buildSessionPayload(updatedAuth),
});
@@ -2492,6 +2516,9 @@ app.post('/api/birds', requireAuth, requireWriteAccess, requireWorkspaceRole(['o
name: parsed.data.name,
tagId: normalizeBandId(parsed.data.tagId),
species: parsed.data.species,
motivators: emptyToNull(parsed.data.motivators),
demotivators: emptyToNull(parsed.data.demotivators),
favoriteSnack: emptyToNull(parsed.data.favoriteSnack),
gender: (parsed.data.gender ?? 'unknown') as BirdGender,
dateOfBirth: emptyToNull(parsed.data.dateOfBirth),
gotchaDay: emptyToNull(parsed.data.gotchaDay),
@@ -2613,6 +2640,9 @@ app.put('/api/birds/:birdId', requireAuth, requireWriteAccess, requireWorkspaceR
name: parsed.data.name,
tagId: normalizeBandId(parsed.data.tagId),
species: parsed.data.species,
motivators: emptyToNull(parsed.data.motivators),
demotivators: emptyToNull(parsed.data.demotivators),
favoriteSnack: emptyToNull(parsed.data.favoriteSnack),
gender: (parsed.data.gender ?? 'unknown') as BirdGender,
dateOfBirth: emptyToNull(parsed.data.dateOfBirth),
gotchaDay: emptyToNull(parsed.data.gotchaDay),