diff --git a/src/components/common/PlatformMultiSelect.tsx b/src/components/common/PlatformMultiSelect.tsx new file mode 100644 index 0000000..377ac41 --- /dev/null +++ b/src/components/common/PlatformMultiSelect.tsx @@ -0,0 +1,48 @@ +import { cn } from "@/utils/cn" + +const PLATFORM_OPTIONS = [ + { value: "web", label: "Web" }, + { value: "android", label: "Android" }, + { value: "ios", label: "iOS" }, +] + +interface PlatformMultiSelectProps { + value: string[] + onChange: (platforms: string[]) => void + id?: string +} + +export function PlatformMultiSelect({ value, onChange, id }: PlatformMultiSelectProps) { + function toggle(platform: string) { + onChange( + value.includes(platform) + ? value.filter((p) => p !== platform) + : [...value, platform], + ) + } + + return ( +
+ {PLATFORM_OPTIONS.map((opt) => { + const active = value.includes(opt.value) + return ( + + ) + })} +
+ ) +} diff --git a/src/components/pages/AppDetailPage.tsx b/src/components/pages/AppDetailPage.tsx index aea0a82..b1d9330 100644 --- a/src/components/pages/AppDetailPage.tsx +++ b/src/components/pages/AppDetailPage.tsx @@ -19,13 +19,6 @@ import { Badge } from "@/components/ui/badge" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" import { Dialog, DialogContent, @@ -38,6 +31,7 @@ import { LoadingSpinner } from "@/components/common/LoadingSpinner" import { EmptyState } from "@/components/common/EmptyState" import { InfoTooltip } from "@/components/common/InfoTooltip" import { ImageUpload } from "@/components/common/ImageUpload" +import { PlatformMultiSelect } from "@/components/common/PlatformMultiSelect" import { ConfirmDialog } from "@/components/common/ConfirmDialog" import { Switch } from "@/components/ui/switch" @@ -236,24 +230,10 @@ function AppRolesTable({ ) } -function legacyToPlatforms(value: string): string[] { - if (value === "both") return ["web", "android", "ios"] - if (value === "mobile") return ["android", "ios"] - return ["web"] -} - -function platformsToLegacy(platforms: string[]): string { - const hasWeb = platforms.includes("web") - const hasMobile = platforms.includes("android") || platforms.includes("ios") - if (hasWeb && hasMobile) return "both" - if (hasMobile) return "mobile" - return "web" -} - interface AppFormState { name: string description: string - platform: string + platforms: string[] icon_url: string app_url: string ios_url: string @@ -266,7 +246,7 @@ function formFromApp(app: AppResponse): AppFormState { return { name: app.name, description: app.description ?? "", - platform: platformsToLegacy(app.platforms), + platforms: app.platforms, icon_url: app.icon_url ?? "", app_url: app.app_url ?? "", ios_url: app.ios_url ?? "", @@ -289,7 +269,7 @@ export default function AppDetailPage() { const [form, setForm] = useState({ name: "", description: "", - platform: "web", + platforms: ["web"], icon_url: "", app_url: "", ios_url: "", @@ -342,12 +322,16 @@ export default function AppDetailPage() { async function handleSave() { if (!appId || !form.name.trim()) return + if (form.platforms.length === 0) { + toast.error("Select at least one platform") + return + } setSaving(true) try { const { data } = await appsAPI.update(appId, { name: form.name.trim(), description: form.description.trim() || null, - platforms: legacyToPlatforms(form.platform), + platforms: form.platforms, icon_url: form.icon_url.trim() || null, app_url: form.app_url.trim() || null, ios_url: form.ios_url.trim() || null, @@ -497,23 +481,15 @@ export default function AppDetailPage() {
- + setForm((f) => ({ ...f, platforms }))} + />
diff --git a/src/components/pages/AppsPage.tsx b/src/components/pages/AppsPage.tsx index f70c496..d1bc433 100644 --- a/src/components/pages/AppsPage.tsx +++ b/src/components/pages/AppsPage.tsx @@ -10,13 +10,6 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Badge } from "@/components/ui/badge" import { Textarea } from "@/components/ui/textarea" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" import { Dialog, DialogContent, @@ -31,27 +24,14 @@ import { InfoTooltip } from "@/components/common/InfoTooltip" import { FeatureSpotlight } from "@/components/common/FeatureSpotlight" import { ConfirmDialog } from "@/components/common/ConfirmDialog" import { ImageUpload } from "@/components/common/ImageUpload" +import { PlatformMultiSelect } from "@/components/common/PlatformMultiSelect" import { Switch } from "@/components/ui/switch" -function legacyToPlatforms(value: string): string[] { - if (value === "both") return ["web", "android", "ios"] - if (value === "mobile") return ["android", "ios"] - return ["web"] -} - -function platformsToLegacy(platforms: string[]): string { - const hasWeb = platforms.includes("web") - const hasMobile = platforms.includes("android") || platforms.includes("ios") - if (hasWeb && hasMobile) return "both" - if (hasMobile) return "mobile" - return "web" -} - interface AppFormState { app_key: string name: string description: string - platform: string + platforms: string[] icon_url: string app_url: string ios_url: string @@ -63,7 +43,7 @@ const emptyForm: AppFormState = { app_key: "", name: "", description: "", - platform: "web", + platforms: ["web"], icon_url: "", app_url: "", ios_url: "", @@ -76,7 +56,7 @@ function formFromApp(app: AppResponse): AppFormState { app_key: app.app_key, name: app.name, description: app.description ?? "", - platform: platformsToLegacy(app.platforms), + platforms: app.platforms, icon_url: app.icon_url ?? "", app_url: app.app_url ?? "", ios_url: app.ios_url ?? "", @@ -125,13 +105,17 @@ export default function AppsPage() { async function handleSave() { if (!form.name.trim() || (!editingApp && !form.app_key.trim())) return + if (form.platforms.length === 0) { + toast.error("Select at least one platform") + return + } setSaving(true) try { if (editingApp) { await appsAPI.update(editingApp.id, { name: form.name.trim(), description: form.description.trim() || null, - platforms: legacyToPlatforms(form.platform), + platforms: form.platforms, icon_url: form.icon_url.trim() || null, app_url: form.app_url.trim() || null, ios_url: form.ios_url.trim() || null, @@ -144,7 +128,7 @@ export default function AppsPage() { app_key: form.app_key.trim(), name: form.name.trim(), description: form.description.trim() || null, - platforms: legacyToPlatforms(form.platform), + platforms: form.platforms, icon_url: form.icon_url.trim() || null, app_url: form.app_url.trim() || null, ios_url: form.ios_url.trim() || null, @@ -391,23 +375,15 @@ function AppFormDialog({
- + setForm((f) => ({ ...f, platforms }))} + />