diff options
Diffstat (limited to 'components/login/partner-auth-form.tsx')
| -rw-r--r-- | components/login/partner-auth-form.tsx | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/components/login/partner-auth-form.tsx b/components/login/partner-auth-form.tsx new file mode 100644 index 00000000..effd7bd3 --- /dev/null +++ b/components/login/partner-auth-form.tsx @@ -0,0 +1,241 @@ +"use client" + +import * as React from "react" +import { useToast } from "@/hooks/use-toast" +import { useRouter, useParams, usePathname } from "next/navigation" +import { useTranslation } from "@/i18n/client" +import Link from "next/link" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { GlobeIcon, ChevronDownIcon, Loader, Ship } from "lucide-react" +import { languages } from "@/config/language" +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" +import { siteConfig } from "@/config/site" + +import { checkJoinPortal } from "@/lib/vendors/service" +import Image from "next/image" +// ↑ 실제 경로 맞춤 수정 (ex: "@/app/[lng]/actions/joinPortal" 등) + +interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { } + +export function CompanyAuthForm({ className, ...props }: UserAuthFormProps) { + const [isLoading, setIsLoading] = React.useState<boolean>(false) + const router = useRouter() + const { toast } = useToast() + const params = useParams() + const pathname = usePathname() + + const lng = params.lng as string + const { t, i18n } = useTranslation(lng, "login") + + const handleChangeLanguage = (lang: string) => { + const segments = pathname.split("/") + segments[1] = lang + router.push(segments.join("/")) + } + + const currentLanguageText = + i18n.language === "ko" + ? t("languages.korean") + : i18n.language === "ja" + ? t("languages.japanese") + : t("languages.english") + + // --------------------------- + // 1) onSubmit -> 서버 액션 호출 + // --------------------------- + async function onSubmit(event: React.FormEvent<HTMLFormElement>) { + event.preventDefault() + setIsLoading(true) + + const formData = new FormData(event.currentTarget) + const taxID = formData.get("taxid")?.toString().trim() + + if (!taxID) { + toast({ + variant: "destructive", + title: "오류", + description: "Tax ID를 입력해주세요.", + }) + setIsLoading(false) + return + } + + try { + // --------------------------- + // 2) 서버 액션 호출 + // --------------------------- + const result = await checkJoinPortal(taxID) + + if (result.success) { + toast({ + variant: "default", + title: "성공", + description: "가입 신청이 가능합니다", + }) + // 가입 가능 → signup 페이지 이동 + router.push(`/partners/signup?taxID=${taxID}`) + } else { + toast({ + variant: "destructive", + title: "가입이 진행 중이거나 완료된 회사", + description: `${result.data} 에 연락하여 계정 생성 요청을 하시기 바랍니다.`, + }) + } + } catch (error: any) { + console.error(error) + toast({ + variant: "destructive", + title: "오류", + description: "서버 액션 호출에 실패했습니다. 잠시 후 다시 시도해주세요.", + }) + } finally { + setIsLoading(false) + } + } + + return ( + <div className="container relative flex h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0"> + + {/* Left BG 이미지 영역 */} + + <div className="flex flex-col w-full h-screen lg:p-2"> + {/* Top bar */} + <div className="flex items-center justify-between"> + <div className="flex items-center space-x-2"> + {/* <img + src="/images/logo.png" + alt="logo" + className="h-8 w-auto" + /> */} + <Ship className="w-4 h-4" /> + <span className="text-md font-bold">eVCP</span> + </div> + + {/* Remove 'absolute right-4 top-4 ...', just use buttonVariants */} + <Link + href="/login" + className={cn( + buttonVariants({ variant: "ghost" }) + )} + > + Login + </Link> + </div> + <div className="flex-1 flex items-center justify-center"> + <div className="mx-auto w-full flex flex-col space-y-6 sm:w-[350px]"> + <div className="flex flex-col space-y-2 text-center"> + <h1 className="text-2xl font-semibold tracking-tight"> + {t("heading")} + </h1> + <p className="text-sm text-muted-foreground">{t("subheading")}</p> + </div> + + <div className={cn("grid gap-6", className)} {...props}> + <form onSubmit={onSubmit}> + <div className="grid gap-2"> + <div className="grid gap-1"> + <label className="sr-only" htmlFor="taxid"> + Business Number / Tax ID + </label> + <input + id="taxid" + name="taxid" + placeholder="880-81-01710" + type="text" + autoCapitalize="none" + autoComplete="off" + autoCorrect="off" + disabled={isLoading} + className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50" + /> + </div> + <Button type="submit" disabled={isLoading} variant="samsung"> + {isLoading && <Loader className="mr-2 h-4 w-4 animate-spin" />} + {t("joinButton")} + </Button> + + {/* 언어 선택 Dropdown */} + <div className="mx-auto"> + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="ghost" className="flex items-center gap-2"> + <GlobeIcon className="h-4 w-4" /> + <span>{currentLanguageText}</span> + <ChevronDownIcon className="h-4 w-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuRadioGroup + value={i18n.language} + onValueChange={(value) => handleChangeLanguage(value)} + > + {languages.map((v) => ( + <DropdownMenuRadioItem key={v.value} value={v.value}> + {t(v.labelKey)} + </DropdownMenuRadioItem> + ))} + </DropdownMenuRadioGroup> + </DropdownMenuContent> + </DropdownMenu> + </div> + </div> + </form> + </div> + <p className="px-8 text-center text-sm text-muted-foreground"> + {t("agreement")}{" "} + <Link + href="/terms" + className="underline underline-offset-4 hover:text-primary" + > + {t("termsOfService")} + </Link>{" "} + {t("and")}{" "} + <Link + href="/privacy" + className="underline underline-offset-4 hover:text-primary" + > + {t("privacyPolicy")} + </Link> + . + </p> + </div> + </div> + + </div> + + + {/* Right Content */} + <div className="relative hidden h-full flex-col p-10 text-white dark:border-r md:flex"> + {/* Image 컴포넌트로 대체 */} + <div className="absolute inset-0"> + <Image + src="/images/02.jpg" + alt="Background image" + fill + priority + sizes="(max-width: 1024px) 100vw, 50vw" + className="object-cover" + /> + </div> + <div className="relative z-10 mt-auto"> + <blockquote className="space-y-2"> + <p className="text-sm">“{t("blockquote")}”</p> + {/* <footer className="text-sm">SHI</footer> */} + </blockquote> + </div> + </div> + + </div> + ) +}
\ No newline at end of file |
