Skip to content

Commit 04d808a

Browse files
committed
fix(ux): show Stripe setup link when community has no payout configured
On the event form, price inputs were disabled after selecting a community without Stripe payout verification, with no feedback explaining why. - useCurrencyOptionsForCommunity now returns { options, isLoading } so callers can distinguish loading from "not configured" - FormDescription in event-form.tsx and dashboard-form-prices.tsx now shows three states: no community / community without Stripe / verified - The "not configured" state shows a link to /dashboard/community/{id}/payouts - Added translation keys price-stripe-not-configured and price-stripe-setup-link to en/fr/es locale files Closes #1038
1 parent 0558c75 commit 04d808a

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
@@ -47,6 +47,7 @@ import {
4747
IMAGE_FILE_SIZE_LIMIT_MB,
4848
} from "@/components/features/event/constants";
4949
import { useCurrencyOptionsForCommunity } from "@/lib/pricing";
50+
import Link from "next/link";
5051

5152
interface EventFormProps {
5253
form: UseFormReturn<EventFormSchemaType>;
@@ -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)