Reorganiza gestão de usuários e remove dados mock
This commit is contained in:
parent
630110bf3a
commit
dded6d1927
20 changed files with 1863 additions and 1368 deletions
|
|
@ -5,6 +5,7 @@ import { ChangeEvent, useEffect, useMemo, useState } from "react"
|
|||
import { cn } from "@/lib/utils"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { COUNTRY_DIAL_CODES, type CountryDialCode } from "@/lib/country-codes"
|
||||
|
||||
export type CountryOption = {
|
||||
code: string
|
||||
|
|
@ -15,26 +16,7 @@ export type CountryOption = {
|
|||
formatLocal: (digits: string) => string
|
||||
}
|
||||
|
||||
const COUNTRY_OPTIONS: CountryOption[] = [
|
||||
{
|
||||
code: "BR",
|
||||
label: "Brasil",
|
||||
dialCode: "+55",
|
||||
flag: "🇧🇷",
|
||||
maxDigits: 11,
|
||||
formatLocal: formatBrazilPhone,
|
||||
},
|
||||
{
|
||||
code: "US",
|
||||
label: "Estados Unidos",
|
||||
dialCode: "+1",
|
||||
flag: "🇺🇸",
|
||||
maxDigits: 10,
|
||||
formatLocal: formatUsPhone,
|
||||
},
|
||||
]
|
||||
|
||||
const DEFAULT_COUNTRY = COUNTRY_OPTIONS[0]
|
||||
const DEFAULT_COUNTRY_CODE = "BR"
|
||||
|
||||
function formatBrazilPhone(digits: string): string {
|
||||
const cleaned = digits.slice(0, 11)
|
||||
|
|
@ -63,12 +45,18 @@ function extractDigits(value?: string | null): string {
|
|||
|
||||
function findCountryByValue(value?: string | null): CountryOption {
|
||||
const digits = extractDigits(value)
|
||||
return (
|
||||
COUNTRY_OPTIONS.find((option) => {
|
||||
const dialDigits = extractDigits(option.dialCode)
|
||||
return digits.startsWith(dialDigits) && digits.length > dialDigits.length
|
||||
}) ?? DEFAULT_COUNTRY
|
||||
)
|
||||
const dialDigits = extractDigits(DEFAULT_COUNTRY.dialCode)
|
||||
let matched: CountryOption = DEFAULT_COUNTRY
|
||||
let matchedLength = digits.startsWith(dialDigits) ? dialDigits.length : 0
|
||||
for (const option of COUNTRY_OPTIONS) {
|
||||
const optionDialDigits = extractDigits(option.dialCode)
|
||||
if (optionDialDigits.length === 0) continue
|
||||
if (digits.startsWith(optionDialDigits) && optionDialDigits.length > matchedLength) {
|
||||
matched = option
|
||||
matchedLength = optionDialDigits.length
|
||||
}
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
function toLocalDigits(value: string | null | undefined, country: CountryOption): string {
|
||||
|
|
@ -88,9 +76,49 @@ function formatStoredValue(country: CountryOption, localDigits: string): string
|
|||
function placeholderFor(country: CountryOption): string {
|
||||
if (country.code === "BR") return "(11) 91234-5678"
|
||||
if (country.code === "US") return "(555) 123-4567"
|
||||
if (country.code === "CA") return "(416) 123-4567"
|
||||
return "Número de telefone"
|
||||
}
|
||||
|
||||
function formatGenericPhone(digits: string): string {
|
||||
const cleaned = digits.slice(0, 15)
|
||||
if (!cleaned) return ""
|
||||
return cleaned.replace(/(\d{3,4})(?=\d)/g, "$1 ").trim()
|
||||
}
|
||||
|
||||
function flagEmojiFor(code: string): string {
|
||||
if (!code || code.length !== 2) return "🏳️"
|
||||
const base = 127397
|
||||
const chars = Array.from(code.toUpperCase()).map((char) => base + char.charCodeAt(0))
|
||||
return String.fromCodePoint(...chars)
|
||||
}
|
||||
|
||||
const regionDisplayNames =
|
||||
typeof Intl !== "undefined" && "DisplayNames" in Intl
|
||||
? new Intl.DisplayNames(["pt-BR", "pt", "en"], { type: "region" })
|
||||
: null
|
||||
|
||||
const SPECIAL_FORMATS: Record<string, { maxDigits: number; formatLocal: (digits: string) => string }> = {
|
||||
BR: { maxDigits: 11, formatLocal: formatBrazilPhone },
|
||||
US: { maxDigits: 10, formatLocal: formatUsPhone },
|
||||
CA: { maxDigits: 10, formatLocal: formatUsPhone },
|
||||
}
|
||||
|
||||
const COUNTRY_OPTIONS: CountryOption[] = COUNTRY_DIAL_CODES.map((entry: CountryDialCode) => {
|
||||
const special = SPECIAL_FORMATS[entry.code]
|
||||
return {
|
||||
code: entry.code,
|
||||
label: regionDisplayNames?.of(entry.code) ?? entry.name ?? entry.code,
|
||||
dialCode: entry.dialCode,
|
||||
flag: flagEmojiFor(entry.code),
|
||||
maxDigits: special?.maxDigits ?? 15,
|
||||
formatLocal: special?.formatLocal ?? formatGenericPhone,
|
||||
}
|
||||
}).sort((a, b) => a.label.localeCompare(b.label, "pt-BR"))
|
||||
|
||||
const DEFAULT_COUNTRY =
|
||||
COUNTRY_OPTIONS.find((option) => option.code === DEFAULT_COUNTRY_CODE) ?? COUNTRY_OPTIONS[0]
|
||||
|
||||
export function PhoneInput({ value, onChange, className, id, name }: PhoneInputProps) {
|
||||
const [selectedCountry, setSelectedCountry] = useState<CountryOption>(DEFAULT_COUNTRY)
|
||||
const [localDigits, setLocalDigits] = useState<string>("")
|
||||
|
|
@ -131,7 +159,7 @@ export function PhoneInput({ value, onChange, className, id, name }: PhoneInputP
|
|||
</span>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectContent className="max-h-72 overflow-y-auto">
|
||||
{COUNTRY_OPTIONS.map((option) => (
|
||||
<SelectItem key={option.code} value={option.code}>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue