11"use client" ;
22
3+ import { Link } from "@/components/link" ;
34import { ItemDialog } from "@/components/payments/item-dialog" ;
45import { useRouter } from "@/components/router" ;
56import {
@@ -26,7 +27,7 @@ import {
2627} from "@/components/ui" ;
2728import { useUpdateConfig } from "@/lib/config-update" ;
2829import { cn } from "@/lib/utils" ;
29- import { ArrowLeftIcon , BuildingOfficeIcon , CaretDownIcon , ChatIcon , ClockIcon , CodeIcon , CopyIcon , GearIcon , HardDriveIcon , LightningIcon , PlusIcon , PuzzlePieceIcon , StackIcon , TrashIcon , UserIcon } from "@phosphor-icons/react" ;
30+ import { ArrowLeftIcon , ArrowSquareOutIcon , BuildingOfficeIcon , CaretDownIcon , ChatIcon , ClockIcon , CodeIcon , CopyIcon , GearIcon , HardDriveIcon , LightningIcon , PlusIcon , PuzzlePieceIcon , StackIcon , TrashIcon , UserIcon } from "@phosphor-icons/react" ;
3031import { CompleteConfig } from "@stackframe/stack-shared/dist/config/schema" ;
3132import { getUserSpecifiedIdErrorMessage , isValidUserSpecifiedId , sanitizeUserSpecifiedId } from "@stackframe/stack-shared/dist/schema-fields" ;
3233import { typedEntries } from "@stackframe/stack-shared/dist/utils/objects" ;
@@ -70,13 +71,48 @@ const CUSTOMER_TYPE_OPTIONS = [
7071 } ,
7172] as const ;
7273
74+ const COLOR_CLASSES = {
75+ blue : {
76+ hover : 'hover:border-blue-500/40 hover:shadow-[0_0_12px_rgba(59,130,246,0.1)]' ,
77+ bg : 'bg-blue-500/10 dark:bg-blue-500/[0.15] group-hover:bg-blue-500/20' ,
78+ icon : 'text-blue-600 dark:text-blue-400' ,
79+ } ,
80+ emerald : {
81+ hover : 'hover:border-emerald-500/40 hover:shadow-[0_0_12px_rgba(16,185,129,0.1)]' ,
82+ bg : 'bg-emerald-500/10 dark:bg-emerald-500/[0.15] group-hover:bg-emerald-500/20' ,
83+ icon : 'text-emerald-600 dark:text-emerald-400' ,
84+ } ,
85+ amber : {
86+ hover : 'hover:border-amber-500/40 hover:shadow-[0_0_12px_rgba(245,158,11,0.1)]' ,
87+ bg : 'bg-amber-500/10 dark:bg-amber-500/[0.15] group-hover:bg-amber-500/20' ,
88+ icon : 'text-amber-600 dark:text-amber-400' ,
89+ } ,
90+ gray : {
91+ hover : '' ,
92+ bg : 'bg-foreground/[0.05]' ,
93+ icon : 'text-foreground/40' ,
94+ } ,
95+ } as const ;
96+
7397function CustomerTypeSelection ( {
7498 onSelectCustomerType,
7599 onCancel,
100+ isTeamsEnabled,
101+ projectId,
76102} : {
77103 onSelectCustomerType : ( type : 'user' | 'team' | 'custom' ) => void ,
78104 onCancel : ( ) => void ,
105+ isTeamsEnabled : boolean ,
106+ projectId : string ,
79107} ) {
108+ // Split options into available and unavailable
109+ const availableOptions = CUSTOMER_TYPE_OPTIONS . filter (
110+ ( option ) => option . value !== 'team' || isTeamsEnabled
111+ ) ;
112+ const unavailableOptions = CUSTOMER_TYPE_OPTIONS . filter (
113+ ( option ) => option . value === 'team' && ! isTeamsEnabled
114+ ) ;
115+
80116 return (
81117 < div className = "flex flex-col h-full" >
82118 < div className = "flex items-center gap-4 px-6 py-4 border-b border-border/40" >
@@ -97,26 +133,11 @@ function CustomerTypeSelection({
97133 < Typography type = "h2" className = "text-2xl font-semibold" > Who will this product be for?</ Typography >
98134 </ div >
99135
136+ { /* Available options */ }
100137 < div className = "grid gap-3" >
101- { CUSTOMER_TYPE_OPTIONS . map ( ( option ) => {
138+ { availableOptions . map ( ( option ) => {
102139 const Icon = option . icon ;
103- const colorClasses = {
104- blue : {
105- hover : 'hover:border-blue-500/40 hover:shadow-[0_0_12px_rgba(59,130,246,0.1)]' ,
106- bg : 'bg-blue-500/10 dark:bg-blue-500/[0.15] group-hover:bg-blue-500/20' ,
107- icon : 'text-blue-600 dark:text-blue-400' ,
108- } ,
109- emerald : {
110- hover : 'hover:border-emerald-500/40 hover:shadow-[0_0_12px_rgba(16,185,129,0.1)]' ,
111- bg : 'bg-emerald-500/10 dark:bg-emerald-500/[0.15] group-hover:bg-emerald-500/20' ,
112- icon : 'text-emerald-600 dark:text-emerald-400' ,
113- } ,
114- amber : {
115- hover : 'hover:border-amber-500/40 hover:shadow-[0_0_12px_rgba(245,158,11,0.1)]' ,
116- bg : 'bg-amber-500/10 dark:bg-amber-500/[0.15] group-hover:bg-amber-500/20' ,
117- icon : 'text-amber-600 dark:text-amber-400' ,
118- } ,
119- } [ option . color ] ;
140+ const colorClasses = COLOR_CLASSES [ option . color ] ;
120141
121142 return (
122143 < Card
@@ -150,6 +171,59 @@ function CustomerTypeSelection({
150171 ) ;
151172 } ) }
152173 </ div >
174+
175+ { /* Unavailable options section */ }
176+ { unavailableOptions . length > 0 && (
177+ < div className = "space-y-2 pt-8" >
178+ < Typography type = "label" className = "text-xs text-foreground/40 uppercase tracking-wider" >
179+ Unavailable options
180+ </ Typography >
181+ < p className = "text-xs text-muted-foreground mb-3" >
182+ These options require additional apps or configuration.
183+ </ p >
184+ < div className = "grid gap-3" >
185+ { unavailableOptions . map ( ( option ) => {
186+ const Icon = option . icon ;
187+ const colorClasses = COLOR_CLASSES . gray ;
188+
189+ return (
190+ < Link
191+ key = { option . value }
192+ href = { `/projects/${ projectId } /apps/teams` }
193+ >
194+ < Card
195+ className = { cn (
196+ "cursor-pointer group" ,
197+ "rounded-xl border border-border/30 dark:border-foreground/[0.05]" ,
198+ "bg-foreground/[0.01] hover:bg-foreground/[0.03]" ,
199+ "opacity-60 hover:opacity-80" ,
200+ "transition-all duration-150 hover:transition-none"
201+ ) }
202+ >
203+ < CardHeader className = "p-4" >
204+ < div className = "flex items-center gap-3" >
205+ < div className = { cn (
206+ "p-2.5 rounded-xl" ,
207+ colorClasses . bg
208+ ) } >
209+ < Icon className = { cn ( "h-5 w-5" , colorClasses . icon ) } />
210+ </ div >
211+ < div className = "flex-1" >
212+ < CardTitle className = "text-base font-semibold text-foreground/50" > { option . label } </ CardTitle >
213+ < CardDescription className = "text-sm mt-1 text-muted-foreground/70" >
214+ Enable the Teams app to choose this customer type
215+ </ CardDescription >
216+ </ div >
217+ < ArrowSquareOutIcon className = "h-4 w-4 text-foreground/30" />
218+ </ div >
219+ </ CardHeader >
220+ </ Card >
221+ </ Link >
222+ ) ;
223+ } ) }
224+ </ div >
225+ </ div >
226+ ) }
153227 </ div >
154228 </ div >
155229 </ div >
@@ -458,12 +532,17 @@ export default function PageClient() {
458532 }
459533 } ;
460534
535+ // Check if Teams app is enabled
536+ const isTeamsEnabled = config . apps . installed . teams ?. enabled ?? false ;
537+
461538 // Show customer type selection if not selected yet
462539 if ( ! hasSelectedCustomerType ) {
463540 return (
464541 < CustomerTypeSelection
465542 onSelectCustomerType = { handleSelectCustomerType }
466543 onCancel = { handleCancel }
544+ isTeamsEnabled = { isTeamsEnabled }
545+ projectId = { projectId }
467546 />
468547 ) ;
469548 }
0 commit comments