| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- 'use client';
- import { useEffect, useState } from 'react';
- import { fetchApi } from '@/lib/utils/client';
- import { Input } from '@/components/ui/input';
- import { Label } from '@/components/ui/label';
- import { Button } from '@/components/ui/button';
- import type { StudioSettingsResponse } from '@/types/response/studio/settings';
- const CODE_PATTERN = /^[A-Za-z0-9]{4,7}$/;
- type IssueResponse = {
- donationCode: string;
- };
- export default function StudioDonationCodePage()
- {
- const [loading, setLoading] = useState(true);
- const [existingCode, setExistingCode] = useState<string|null>(null);
- const [input, setInput] = useState('');
- const [submitting, setSubmitting] = useState(false);
- const [error, setError] = useState<string|null>(null);
- useEffect(() => {
- fetchApi<StudioSettingsResponse>('/api/studio/settings')
- .then(res => {
- if (res.data) {
- setExistingCode(res.data.donationCode);
- }
- })
- .catch(() => {})
- .finally(() => {
- setLoading(false);
- });
- }, []);
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- const trimmed = input.trim();
- if (!CODE_PATTERN.test(trimmed)) {
- setError('후원 코드는 4~7자 영문/숫자만 가능합니다.');
- return;
- }
- const normalized = trimmed.toUpperCase();
- const ok = window.confirm(`후원 코드 "${normalized}" 로 등록합니다.\n한 번 등록하면 변경할 수 없습니다. 진행하시겠습니까?`);
- if (!ok) {
- return;
- }
- setSubmitting(true);
- setError(null);
- const res = await fetchApi<IssueResponse>('/api/studio/donation-code', {
- method: 'POST',
- body: { code: normalized },
- silent: true
- });
- if (res.success && res.data) {
- setExistingCode(res.data.donationCode);
- setInput('');
- window.alert(`후원 코드 "${res.data.donationCode}" 가 정상적으로 등록되었습니다.`);
- }
- else {
- setError(res.message || '후원 코드 발급에 실패했습니다.');
- }
- setSubmitting(false);
- };
- if (loading) {
- return (
- <div className="studio-page">
- <p className="text-sm text-muted-foreground">불러오는 중...</p>
- </div>
- );
- }
- return (
- <div className="studio-page">
- <div className="mb-6">
- <h1 className="text-2xl font-bold mb-3">후원 코드</h1>
- <p className="mt-1 text-sm text-muted-foreground leading-relaxed">
- 후원 코드는 시청자가 후원 채널을 빠르게 찾도록 도와줍니다. 4~7자 영문/숫자만 가능하며, 대소문자 구분 없이 대문자로 저장됩니다.
- <br />
- 한 번 등록하면 <span className="font-semibold text-foreground">변경할 수 없습니다.</span>
- </p>
- </div>
- {existingCode !== null ? (
- <div className="max-w-md rounded-md border border-input bg-background p-5">
- <Label htmlFor="code-readonly" className="text-sm">
- 등록된 후원 코드
- </Label>
- <Input
- id="code-readonly"
- value={existingCode}
- readOnly
- className="mt-2 font-mono text-base tracking-widest"
- />
- <p className="mt-2 text-xs text-muted-foreground">
- * 이미 등록되어 변경할 수 없습니다.
- </p>
- </div>
- ) : (
- <form onSubmit={handleSubmit} className="max-w-md space-y-4 rounded-md border border-input bg-background p-5">
- <div>
- <Label htmlFor="code" className="text-sm">
- 후원 코드
- </Label>
- <Input
- id="code"
- value={input}
- onChange={(e) => {
- setInput(e.target.value);
- setError(null);
- }}
- placeholder="예: ABC123"
- maxLength={7}
- autoComplete="off"
- spellCheck={false}
- className="mt-2 font-mono text-base tracking-widest uppercase"
- disabled={submitting}
- />
- <p className="mt-1 text-xs text-muted-foreground">
- * 4~7자 영문/숫자만 사용 가능. 특수문자·한글 불가.
- </p>
- </div>
- {error && (
- <p className="text-xs text-destructive">{error}</p>
- )}
- <Button
- type="submit"
- disabled={submitting || !CODE_PATTERN.test(input.trim())}
- className="w-full"
- >
- {submitting ? '등록 중...' : '등록하기'}
- </Button>
- </form>
- )}
- </div>
- );
- }
|