| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- 'use client';
- import { useEffect, useState } from 'react';
- import { fetchApi } from '@/lib/utils/client';
- import useAuth from '@/hooks/useAuth';
- import { FollowToggleResponse, IsFollowingResponse } from '@/types/account/follow';
- import '@/app/styles/follow-button.scss';
- type Props = {
- memberSID: string;
- initialFollowing?: boolean;
- onChange?: (isFollowing: boolean, followerCount: number) => void;
- className?: string;
- };
- export default function FollowButton({ memberSID, initialFollowing, onChange, className }: Props) {
- const { isAuthenticated, member, loginCheck } = useAuth();
- const [isFollowing, setIsFollowing] = useState<boolean>(initialFollowing ?? false);
- const [loading, setLoading] = useState<boolean>(false);
- const [hydrated, setHydrated] = useState<boolean>(initialFollowing !== undefined);
- const isSelf = member?.sid === memberSID;
- useEffect(() => {
- if (initialFollowing !== undefined) {
- return;
- }
- if (!isAuthenticated || isSelf) {
- setHydrated(true);
- return;
- }
- fetchApi<IsFollowingResponse>('/api/member/follow/check', {
- method: 'POST',
- body: { sids: [memberSID] },
- silent: true
- }).then((res) => {
- setIsFollowing(res.data?.map?.[memberSID] ?? false);
- }).catch(() => {}).finally(() => {
- setHydrated(true);
- });
- }, [isAuthenticated, memberSID, isSelf, initialFollowing]);
- const handleClick = async () => {
- if (!loginCheck()) {
- return;
- }
- if (loading || isSelf) {
- return;
- }
- setLoading(true);
- try {
- const res = await fetchApi<FollowToggleResponse>(`/api/member/${memberSID}/follow`, {
- method: 'POST',
- silent: true
- });
- if (res.success && res.data) {
- setIsFollowing(res.data.isFollowing);
- onChange?.(res.data.isFollowing, res.data.followerCount);
- }
- } catch (err) {
- console.error('Follow toggle failed:', err);
- } finally {
- setLoading(false);
- }
- };
- if (isSelf) {
- return null;
- }
- const label = !hydrated ? '···' : (isFollowing ? '팔로잉' : '팔로우');
- const modifier = isFollowing ? 'follow-button--following' : 'follow-button--default';
- return (
- <button
- type="button"
- onClick={handleClick}
- disabled={loading || !hydrated}
- className={`follow-button ${modifier} ${className ?? ''}`.trim()}
- aria-pressed={isFollowing}
- >
- {label}
- </button>
- );
- }
|