Skip to content

Commit f39264e

Browse files
authored
fix(ux): show Stripe setup link on event form when community has no payout configured (#1040)
## Problem On the event creation/edit form, price inputs stay disabled after selecting a community that has not configured Stripe payout. The helper text "Select a community to set a price." never updates, leaving users confused about why inputs are still grayed out even after selecting a community. ## Solution Added a third state to the price helper text: | State | Message | |---|---| | No community selected | "Select a community to set a price." | | Community selected, Stripe **not configured** | "This community has not configured Stripe yet. [Set up payouts →]" | | Community selected, Stripe **verified** | *(no message, price inputs enabled)* | The "Set up payouts →" link redirects to `/dashboard/community/{id}/payouts`. ## Changes - **`lib/pricing.ts`** — `useCurrencyOptionsForCommunity` now returns `{ options, isLoading }` instead of the raw array, so callers can avoid flashing the "not configured" message during the payout status fetch. - **`components/features/event/event-form.tsx`** — updated `FormDescription` to 3-state display with the Stripe setup link. - **`components/features/dashboard/event/_components/dashboard-form-prices.tsx`** — same update (second caller of the hook). - **`app/i18n/messages/{en,fr,es}.json`** — added `price-stripe-not-configured` and `price-stripe-setup-link` translation keys. ## How to test 1. Go to `/dashboard/event/create` 2. **Before** selecting a community: see "Select a community to set a price." 3. Select a community **without** Stripe payout configured: message becomes "This community has not configured Stripe yet. Set up payouts →" (price inputs still disabled) 4. Click "Set up payouts →": lands on `/dashboard/community/{id}/payouts` 5. Select a community **with** Stripe verified: price inputs become enabled, no helper message Closes #1038
1 parent e5f8b73 commit f39264e

6 files changed

Lines changed: 49 additions & 11 deletions

File tree

app/i18n/messages/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
"price-free": "Free",
9393
"price-helper": "Leave 0 for a free event.",
9494
"price-community-required": "Select a community to set a price.",
95+
"price-stripe-not-configured": "This community has not configured Stripe yet.",
96+
"price-stripe-setup-link": "Set up payouts",
9597
"discoverable-label": "Make event discoverable (Visible in Discover)",
9698
"exclusive-label": "Exclusive",
9799
"pick-a-start-date-placeholder": "Pick a start date...",
@@ -962,4 +964,4 @@
962964
"description": "Discover the latest articles, news, and updates about Zenao in our blog."
963965
}
964966
}
965-
}
967+
}

app/i18n/messages/es.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
"price-free": "Gratis",
9393
"price-helper": "Deja 0 para un evento gratuito.",
9494
"price-community-required": "Selecciona una comunidad para establecer un precio.",
95+
"price-stripe-not-configured": "Esta comunidad aún no ha configurado Stripe.",
96+
"price-stripe-setup-link": "Configurar pagos",
9597
"discoverable-label": "Hacer evento descubrible (Visible en Descubrir)",
9698
"exclusive-label": "Exclusivo",
9799
"pick-a-start-date-placeholder": "Elige una fecha de inicio...",
@@ -962,4 +964,4 @@
962964
"description": "Descubre los últimos artículos, noticias y actualizaciones sobre Zenao en nuestro blog."
963965
}
964966
}
965-
}
967+
}

app/i18n/messages/fr.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
"price-free": "Gratuit",
9393
"price-helper": "Laissez 0 pour un événement gratuit.",
9494
"price-community-required": "Sélectionnez une communauté pour définir un prix.",
95+
"price-stripe-not-configured": "Cette communauté n'a pas encore configuré Stripe.",
96+
"price-stripe-setup-link": "Configurer les paiements",
9597
"discoverable-label": "Rendre l'événement visible publiquement (Visible dans Découvrir)",
9698
"exclusive-label": "Exclusif",
9799
"pick-a-start-date-placeholder": "Choisir une date de début...",
@@ -962,4 +964,4 @@
962964
"description": "Découvrez les derniers articles, nouvelles et mises à jour de Zenao sur notre blog."
963965
}
964966
}
965-
}
967+
}

components/features/dashboard/event/_components/dashboard-form-prices.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useFieldArray, useFormContext } from "react-hook-form";
22
import { useTranslations } from "next-intl";
3+
import Link from "next/link";
34
import { EventFormSchemaType } from "@/types/schemas";
45
import { PriceGroupFieldSet } from "@/components/features/event/price-group-field-set";
56
import { FormDescription } from "@/components/shadcn/form";
@@ -10,7 +11,8 @@ export default function DashboardFormPrices() {
1011
const form = useFormContext<EventFormSchemaType>();
1112
const communityID = form.watch("communityId");
1213

13-
const currencyOptions = useCurrencyOptionsForCommunity(communityID);
14+
const { options: currencyOptions, isLoading: payoutLoading } =
15+
useCurrencyOptionsForCommunity(communityID);
1416

1517
const { fields: priceGroupFields } = useFieldArray({
1618
control: form.control,
@@ -32,7 +34,20 @@ export default function DashboardFormPrices() {
3234
)}
3335
<FormDescription>
3436
{t("price-helper")}
35-
{!communityID ? ` ${t("price-community-required")}` : ""}
37+
{!communityID ? (
38+
` ${t("price-community-required")}`
39+
) : !payoutLoading && currencyOptions.length < 2 ? (
40+
<>
41+
{" "}
42+
{t("price-stripe-not-configured")}{" "}
43+
<Link
44+
href={`/dashboard/community/${communityID}/payouts`}
45+
className="text-main hover:underline"
46+
>
47+
{t("price-stripe-setup-link")}
48+
</Link>
49+
</>
50+
) : null}
3651
</FormDescription>
3752
</>
3853
);

components/features/event/event-form.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Link from "next/link";
12
import { UseFormReturn, useFieldArray } from "react-hook-form";
23
import { useTranslations } from "next-intl";
34
import { useEffect, useMemo, useRef, useState } from "react";
@@ -91,7 +92,8 @@ export const EventForm: React.FC<EventFormProps> = ({
9192
const isCustom = useMemo(() => !isVirtual && !marker, [isVirtual, marker]);
9293
const eventTimezone = locationTimezone(location);
9394
const timeZone = useLayoutTimezone(eventTimezone);
94-
const currencyOptions = useCurrencyOptionsForCommunity(communityId);
95+
const { options: currencyOptions, isLoading: payoutLoading } =
96+
useCurrencyOptionsForCommunity(communityId);
9597

9698
// Upload
9799
const descriptionRef = useRef<HTMLTextAreaElement>(null);
@@ -422,7 +424,20 @@ export const EventForm: React.FC<EventFormProps> = ({
422424
))}
423425
<FormDescription>
424426
{t("price-helper")}
425-
{!communityId ? ` ${t("price-community-required")}` : ""}
427+
{!communityId ? (
428+
` ${t("price-community-required")}`
429+
) : !payoutLoading && currencyOptions.length < 2 ? (
430+
<>
431+
{" "}
432+
{t("price-stripe-not-configured")}{" "}
433+
<Link
434+
href={`/dashboard/community/${communityId}/payouts`}
435+
className="text-main hover:underline"
436+
>
437+
{t("price-stripe-setup-link")}
438+
</Link>
439+
</>
440+
) : null}
426441
</FormDescription>
427442
<FormFieldDatePicker
428443
name="startDate"

lib/pricing.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,24 @@ export const formatPrice = (
9999

100100
export const useCurrencyOptionsForCommunity = (communityId: string | null) => {
101101
const { getToken } = useAuth();
102-
const { data: payoutStatus } = useQuery({
102+
const { data: payoutStatus, isLoading } = useQuery({
103103
...communityPayoutStatus(communityId ?? "", getToken),
104104
enabled: !!communityId,
105105
});
106106

107107
const t = useTranslations("eventForm");
108108

109-
return useMemo(() => {
109+
const options = useMemo(() => {
110110
const currencies =
111111
payoutStatus?.verificationState == VerificationState.verified
112112
? payoutStatus?.currencies
113113
: [];
114-
const options = currencies.map((currency) => ({
114+
const mapped = currencies.map((currency) => ({
115115
value: currency.toUpperCase(),
116116
label: currency.toUpperCase(),
117117
}));
118-
return [{ value: "", label: t("currency-free-option") }, ...options];
118+
return [{ value: "", label: t("currency-free-option") }, ...mapped];
119119
}, [payoutStatus?.currencies, payoutStatus?.verificationState, t]);
120+
121+
return { options, isLoading: !!communityId && isLoading };
120122
};

0 commit comments

Comments
 (0)