diff --git a/apps/dashboard/src/@/components/ui/DynamicHeight.tsx b/apps/dashboard/src/@/components/ui/DynamicHeight.tsx index d2bb3b91e78..4835281db51 100644 --- a/apps/dashboard/src/@/components/ui/DynamicHeight.tsx +++ b/apps/dashboard/src/@/components/ui/DynamicHeight.tsx @@ -17,9 +17,7 @@ export function DynamicHeight(props: { boxSizing: "border-box", height: height ? `${height}px` : "auto", overflow: "hidden", - transition: - props.transition || - "height 210ms cubic-bezier(0.175, 0.885, 0.32, 1.1)", + transition: props.transition || "height 250ms ease", }} >
- + {props.checked === "indeterminate" ? ( + + ) : ( + + )} )); diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx index ee84c438bd0..30194d44594 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx @@ -3,7 +3,6 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation } from "@tanstack/react-query"; import type { ProjectEmbeddedWalletsService } from "@thirdweb-dev/service-utils"; import { CircleAlertIcon, PlusIcon, Trash2Icon } from "lucide-react"; -import Link from "next/link"; import type React from "react"; import { useState } from "react"; import { type UseFormReturn, useFieldArray, useForm } from "react-hook-form"; @@ -240,11 +239,7 @@ export const InAppWalletSettingsUI: React.FC< return (
- + {/* Branding */} - + {/* Authentication */} -
+
+ +
+ } + > -
+
-
+
- -
- -
); @@ -302,14 +306,22 @@ function BrandingFieldset(props: { teamSlug: string; requiredPlan: Team["billingPlan"]; client: ThirdwebClient; + isUpdating: boolean; }) { return ( -
- + + +
+ } + > +
- +
- {/* Application Image */} - ( - - Application Image URL - - Logo that will display in the emails sent to users.{" "} -
The image must be squared with - recommended size of 72x72 px. -
- - { - props.form.setValue("branding.applicationImageUrl", uri, { - shouldDirty: true, - shouldTouch: true, - }); - }} - uri={props.form.watch("branding.applicationImageUrl")} - /> - - -
- )} - /> +
+ ( + +
+ Application Image URL + + Logo that will display in the emails sent to users.{" "} +
The image must be squared + with recommended size of 72x72 px. +
+ + +
+ + + { + props.form.setValue("branding.applicationImageUrl", uri, { + shouldDirty: true, + shouldTouch: true, + }); + }} + uri={props.form.watch("branding.applicationImageUrl")} + /> + +
+ )} + /> - {/* Application Name */} - ( - - Application Name - - Name that will be displayed in the emails sent to users.{" "} -
Defaults to your API Key's - name. -
- - - - -
- )} - /> + {/* Application Name */} + ( + + Application Name + + Name that will be displayed in the emails sent to users.{" "} +
Defaults to your API Key's + name. +
+ + + + +
+ )} + /> +
- + ); } @@ -418,7 +435,7 @@ function AppImageFormControl(props: {
{ @@ -514,14 +531,13 @@ function JSONWebTokenFields(props: { description={ <> Optionally allow users to authenticate with a custom JWT.{" "} - Learn more - + } switchId="authentication-switch" @@ -606,14 +622,13 @@ function AuthEndpointFields(props: { <> Optionally allow users to authenticate with any arbitrary payload that you provide.{" "} - Learn more - + } switchId="auth-endpoint-switch" @@ -743,10 +758,21 @@ function AuthEndpointFieldsContent(props: { function NativeAppsFieldset(props: { form: UseFormReturn; + isUpdating: boolean; }) { const { form } = props; return ( -
+
+ +
+ } + > {props.children}
; + return ( +
+ {props.children} +
+ ); +} + +function Fieldset(props: { + legend: string; + children: React.ReactNode; + footer?: React.ReactNode; +}) { + return ( +
+ +
+ {/* put inside div to remove default styles on legend */} +
+ {props.legend} +
+ + {props.children} +
+
+ {props.footer} +
+ ); } -function Fieldset(props: { legend: string; children: React.ReactNode }) { +function FieldsetWithDescription(props: { + legend: string; + children: React.ReactNode; + footer?: React.ReactNode; + description: React.ReactNode; +}) { return ( - -
- {/* put inside div to remove default styles on legend */} -
- {props.legend} -
+
+ +
+ {/* put inside div to remove default styles on legend */} +
+ + {props.legend} + +

{props.description}

+
- {props.children} -
-
+ {props.children} +
+
+ {props.footer} +
); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx index a8dbbf57552..da376e2c3b0 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx @@ -1,6 +1,8 @@ /** biome-ignore-all lint/a11y/useSemanticElements: EXPECTED */ -import { CheckIcon, MinusIcon } from "lucide-react"; +import { CheckIcon, ChevronDownIcon } from "lucide-react"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { cn } from "@/lib/utils"; import type { SMSCountryTiers } from "../../api/sms"; @@ -31,17 +33,6 @@ export default function CountrySelector({ return tierCountries.every((country) => isCountrySelected(country)); }; - // Check if some countries in a tier are selected - const isTierIndeterminate = (tier: string) => { - const tierCountries = countryTiers[tier as keyof typeof countryTiers]; - const selectedInTier = tierCountries.filter((country) => - isCountrySelected(country), - ); - return ( - selectedInTier.length > 0 && selectedInTier.length < tierCountries.length - ); - }; - // Toggle a tier selection const toggleTier = (tier: string) => { const tierCountries = countryTiers[tier as keyof typeof countryTiers]; @@ -81,101 +72,144 @@ export default function CountrySelector({ onChange(newSelected); }; - // Get selected countries count for a tier - const getSelectedCountInTier = (tier: string) => { - const tierCountries = countryTiers[tier as keyof typeof countryTiers]; - return tierCountries.filter((country) => isCountrySelected(country)).length; - }; + return ( +
+ {Object.entries(countryTiers).map(([tier, tierCountries], index) => { + const selectedTierCountries = tierCountries.filter((country) => + isCountrySelected(country), + ); + + return ( + toggleTier(tier)} + tierCountries={tierCountries} + selectedTierCountries={selectedTierCountries} + onToggleCountry={toggleCountry} + /> + ); + })} +
+ ); +} + +function TierCard(props: { + tier: string; + tierIndex: number; + onToggleTier: () => void; + tierCountries: string[]; + selectedTierCountries: string[]; + onToggleCountry: (country: string) => void; +}) { + const { + tier, + tierIndex, + onToggleTier, + tierCountries: countries, + selectedTierCountries: selectedCountries, + onToggleCountry, + } = props; + + const [isExpanded, setIsExpanded] = useState(true); + const isPartiallySelected = + selectedCountries.length > 0 && selectedCountries.length < countries.length; + const isTierFullySelected = selectedCountries.length === countries.length; return ( -
- {Object.entries(countryTiers).map(([tier, countries], index) => ( -
-
-
- toggleTier(tier)} - /> - {isTierIndeterminate(tier) && ( - - )} -
- - - {tierPricing[tier as keyof typeof tierPricing]} +
+ {/* header */} +
+ {/* left */} +
+ + + + {isPartiallySelected && ( + + ({selectedCountries.length}/{countries.length}) -
+ )} +
-
+ - {countries.map((country) => ( -
+ + +
+
+ + {/* body */} + {isExpanded && ( +
+ {countries.map((country) => { + const isSelected = selectedCountries.includes(country); + return ( +
+ {isSelected && } + + ); + })}
- ))} + )}
); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts index 89943daa541..b43d8694c12 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts @@ -117,14 +117,14 @@ export const countryNames: Record = { KG: "Kyrgyzstan", KH: "Cambodia", KI: "Kiribati", - KN: "St Kitts and Nevis", - KR: "Korea Republic of", + KN: "Saint Kitts and Nevis", + KR: "South Korea", KW: "Kuwait", KY: "Cayman Islands", KZ: "Kazakhstan", LA: "Laos PDR", LB: "Lebanon", - LC: "St Lucia", + LC: "Saint Lucia", LI: "Liechtenstein", LK: "Sri Lanka", LR: "Liberia", @@ -139,7 +139,7 @@ export const countryNames: Record = { ME: "Montenegro", MG: "Madagascar", MH: "Marshall Islands", - MK: "Macedonia", + MK: "North Macedonia", ML: "Mali", MM: "Myanmar", MN: "Mongolia", @@ -172,14 +172,14 @@ export const countryNames: Record = { PH: "Philippines", PK: "Pakistan", PL: "Poland", - PM: "St Pierre and Miquelon", + PM: "Saint Pierre and Miquelon", PR: "Puerto Rico", PS: "Palestinian Territory", PT: "Portugal", PW: "Palau", PY: "Paraguay", QA: "Qatar", - RE: "Reunion/Mayotte", + RE: "Réunion", RO: "Romania", RS: "Serbia", RW: "Rwanda", @@ -200,7 +200,7 @@ export const countryNames: Record = { ST: "Sao Tome and Principe", SV: "El Salvador", SY: "Syria", - SZ: "Swaziland", + SZ: "Eswatini", TC: "Turks and Caicos Islands", TD: "Chad", TG: "Togo", @@ -217,7 +217,7 @@ export const countryNames: Record = { UG: "Uganda", US: "United States", UY: "Uruguay", - VC: "St Vincent Grenadines", + VC: "Saint Vincent and the Grenadines", VE: "Venezuela", VG: "Virgin Islands, British", VI: "Virgin Islands, U.S.",