summaryrefslogtreecommitdiff
path: root/components/ui/back-button.tsx
blob: 364c0b96347ce06f9ab2974bf1aa1cab592ddc34 (plain)
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"use client"

import * as React from "react"
import { useRouter, usePathname } from "next/navigation"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"

/**
 * BackButton 컴포넌트 - 세그먼트를 동적으로 제거하여 상위 경로로 이동
 * 
 * 사용 예시:
 * 
 * // 기본 사용 (1개 세그먼트 제거)
 * <BackButton>목록으로</BackButton>
 * 
 * // 2개 세그먼트 제거 (/a/b/c/d -> /a/b)
 * <BackButton segmentsToRemove={2}>상위 목록으로</BackButton>
 * 
 * // 커스텀 경로로 이동
 * <BackButton customPath="/dashboard">대시보드로</BackButton>
 * 
 * // 아이콘 없이 사용
 * <BackButton showIcon={false}>돌아가기</BackButton>
 * 
 * // 커스텀 스타일링
 * <BackButton className="text-blue-600" variant="outline">
 *   이전 페이지
 * </BackButton>
 */

interface BackButtonProps extends React.ComponentPropsWithoutRef<typeof Button> {
  /**
   * 제거할 세그먼트 개수 (기본값: 1)
   * 예: segmentsToRemove=1이면 /a/b/c -> /a/b
   *     segmentsToRemove=2이면 /a/b/c -> /a
   */
  segmentsToRemove?: number
  
  /**
   * 버튼에 표시할 텍스트 (기본값: "목록으로")
   */
  children?: React.ReactNode
  
  /**
   * 아이콘을 표시할지 여부 (기본값: true)
   */
  showIcon?: boolean
  
  /**
   * 커스텀 경로를 지정할 경우 (segmentsToRemove 대신 사용)
   */
  customPath?: string
}

export const BackButton = React.forwardRef<
  React.ElementRef<typeof Button>,
  BackButtonProps
>(({ 
  segmentsToRemove = 1, 
  children = "Go Back", 
  showIcon = true,
  customPath,
  className,
  onClick,
  ...props 
}, ref) => {
  const router = useRouter()
  const pathname = usePathname()

  const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
    // 커스텀 onClick이 있으면 먼저 실행
    if (onClick) {
      onClick(event)
      // preventDefault가 호출되었으면 기본 동작 중단
      if (event.defaultPrevented) {
        return
      }
    }

    let targetPath: string

    if (customPath) {
      targetPath = customPath
    } else {
      // 현재 경로에서 세그먼트 제거
      const segments = pathname.split('/').filter(Boolean)
      const newSegments = segments.slice(0, -segmentsToRemove)
      targetPath = newSegments.length > 0 ? `/${newSegments.join('/')}` : '/'
    }

    router.push(targetPath)
  }, [router, pathname, segmentsToRemove, customPath, onClick])

  return (
    <Button
      ref={ref}
      variant="ghost"
      className={cn(
        "flex items-center text-primary hover:text-primary/80 transition-colors p-0 h-auto",
        className
      )}
      onClick={handleClick}
      {...props}
    >
      {showIcon && <ArrowLeft className="mr-1 h-4 w-4" />}
      <span>{children}</span>
    </Button>
  )
})

BackButton.displayName = "BackButton"