All files / src/components/pages/auth/fields/nickname-field index.tsx

0% Statements 0/82
0% Branches 0/1
0% Functions 0/1
0% Lines 0/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83                                                                                                                                                                     
'use client';

import { type AnyFieldApi } from '@tanstack/react-form';

import { FormInput } from '@/components/shared';
import { getHintMessage } from '@/lib/auth/utils';
import { cn } from '@/lib/utils';

interface AvailabilityButtonProps {
  onClick: () => void;
  disabled: boolean;
}

type NicknameCheck = {
  hint?: string;
  state: { status: 'idle' | 'checking' | 'available' | 'unavailable' | 'error' };
  isChecking: boolean;
  check: (value: string) => void | Promise<void>;
  reset: () => void;
};

interface Props {
  field: AnyFieldApi;
  nicknameCheck: NicknameCheck;
}

const AvailabilityButton = ({ onClick, disabled }: AvailabilityButtonProps) => {
  return (
    <button
      className={cn(
        'text-text-xs-semibold absolute top-4 right-5 rounded-lg bg-gray-100 px-3 py-1 text-gray-800',
        disabled && '!cursor-not-allowed',
      )}
      aria-disabled={disabled}
      aria-label='닉네임 중복 확인'
      disabled={disabled}
      type='button'
      onClick={onClick}
    >
      중복 확인
    </button>
  );
};

export const NicknameField = ({ field, nicknameCheck }: Props) => {
  const hintMessage = getHintMessage(field);

  const trimmedValue = field.state.value.trim();
  const hasValidationError = field.state.meta.errors.length > 0;

  const availabilityButtonDisabled =
    !trimmedValue || hasValidationError || nicknameCheck.isChecking;

  const iconButton = (
    <AvailabilityButton
      disabled={availabilityButtonDisabled}
      onClick={() => {
        void nicknameCheck.check(trimmedValue);
      }}
    />
  );

  return (
    <FormInput
      availabilityHint={nicknameCheck.hint}
      availabilityStatus={nicknameCheck.state}
      hintMessage={hintMessage}
      inputProps={{
        type: 'text',
        autoComplete: 'nickname',
        placeholder: '닉네임을 입력해주세요',
        value: field.state.value,
        iconButton: iconButton,
        onChange: (e) => {
          field.handleChange(e.target.value);
          nicknameCheck.reset();
        },
      }}
      labelName='닉네임'
    />
  );
};