Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
72f60e4
refactor: ButtonIcon 서브컴포넌트 제거 ->prop으로 관리할수 있게 변경
seongihun Dec 31, 2025
4935d50
refactor: ButtonIcon 서브컴포넌트 제거 ->prop으로 관리할수 있게 변경
seongihun Dec 31, 2025
453d635
refactor: ref가 prop으로 자동전달 componentPropsWithRef 사용
seongihun Dec 31, 2025
a22c112
🎨 Style: reservation-view SVG 아이콘 추가
Greensod-96 Jan 1, 2026
9543318
🎨 Style: MyInfo 페이지 p-6 패딩 제거
Greensod-96 Jan 1, 2026
e7b1e7f
✨ Feat: ReservationView 구현
Greensod-96 Jan 1, 2026
629c8b3
Merge branch 'develop' into feat/reservation-view
Greensod-96 Jan 1, 2026
93ce5f6
♻️ Refactor: InputField 공통 컴포넌트 구조 정리 및 스타일 통합
Greensod-96 Jan 1, 2026
2bb347b
♻️ Refactor: PasswordInput 컴포넌트 구조 단순화 및 스타일 통합
Greensod-96 Jan 1, 2026
cd9be8a
♻️ Refactor: SearchInput 컴포넌트 구조 단순화 및 스타일 통합
Greensod-96 Jan 1, 2026
55b14fd
♻️ Refactor: Input 컴포넌트 스타일 통합 및 기본 UI 개선
Greensod-96 Jan 1, 2026
d8608da
♻️ Refactor: InputField 구조 단순화 및 children 기반 렌더링 개선
Greensod-96 Jan 1, 2026
19a6003
♻️ Refactor: PasswordInput 스타일 단순화 및 Input 책임 분리
Greensod-96 Jan 1, 2026
2acbb69
♻️ Refactor: SearchInput 스타일 단순화 및 공통 Input 활용
Greensod-96 Jan 1, 2026
1794f38
♻️ Refactor: Input 컴포넌트에 forwardRef 적용
Greensod-96 Jan 1, 2026
4d9aa6a
♻️ Refactor: InputField에 label 연결 및 접근성 개선
Greensod-96 Jan 1, 2026
18eebb0
♻️ Refactor: Input 컴포넌트에서 forwardRef 제거
Greensod-96 Jan 2, 2026
35e9641
♻️ Refactor: InputField에서 inputProps 제거 및 props 구조 단순화
Greensod-96 Jan 2, 2026
1699df1
♻️ Refactor: PasswordInput 컴포넌트 구조 개선 및 접근성 보완
Greensod-96 Jan 2, 2026
7ea8180
♻️ Refactor: SearchInput props 구조 개선
Greensod-96 Jan 2, 2026
5a66ca6
🎨 Style: PasswordInput 아이콘 이미지 alt 속성 제거
Greensod-96 Jan 3, 2026
d8dbaf6
Merge pull request #20 from 5team-gn/feat/reservation-view
Greensod-96 Jan 3, 2026
a18a794
Merge pull request #21 from 5team-gn/refactor/input-components
Greensod-96 Jan 3, 2026
2f1e732
refactor: ButtonIcon 서브컴포넌트 제거 ->prop으로 관리할수 있게 변경
seongihun Dec 31, 2025
b94af9f
refactor: ButtonIcon 서브컴포넌트 제거 ->prop으로 관리할수 있게 변경
seongihun Dec 31, 2025
6950cc1
refactor: ref가 prop으로 자동전달 componentPropsWithRef 사용
seongihun Dec 31, 2025
57bf37c
refactor: 리뷰반영수정
seongihun Jan 3, 2026
38cfe5d
Merge branch 'feat/Button' of https://github.com/5team-gn/GlobalNomad…
seongihun Jan 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions app/myinfo/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ import MyInfoClient from "@/feature/MyInfo/MyInfoClient";

export default function MyInfoPage() {
return (
<Suspense fallback={<div>로딩중...</div>}>
<MyInfoClient />
</Suspense>
<div className="flex min-h-screen">
<div className="flex ml-30 xl:ml-117.5 pt-10">
<Sidebar active={activeMenu} onChange={setActiveMenu} />

<main className="flex-1">
{activeMenu === "MY_INFO" && <MyInfoView />}
{activeMenu === "RESERVATIONS" && <ReservationView />}
{activeMenu === "MY_EXPERIENCE" && <MyExperinenceView />}
{activeMenu === "RESERVATION_STATUS" && <ReservaionStatusView />}
</main>
</div>
</div>
);
}
83 changes: 49 additions & 34 deletions components/button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,77 @@
"use client";

import { ButtonHTMLAttributes, ReactNode } from "react";
import { ReactNode, ComponentPropsWithRef } from "react";
import { cn } from "@/lib/utils/twmerge";
import {
ButtonVariants,
buttonIconVariants,
buttonLabelVariants,
} from "./ButtonVariants";
import { cn } from "@/lib/utils/twmerge";

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary" | "text" | "ghost";
size?: "lg" | "md" | "sm";
}
const DEFAULT_BUTTON_PROPS = {
variant: "primary",
size: "md",
} as const;

interface ButtonSubProps {
type BaseButtonProps = {
variant?: "primary" | "secondary" | "text" | "ghost";
size?: "lg" | "md" | "sm";
className?: string;
children: ReactNode;
}
leftIcon?: ReactNode;
rightIcon?: ReactNode;
};

export const ButtonIcon = ({
variant = "primary",
className,
children,
}: ButtonSubProps) => (
<span className={cn(buttonIconVariants({ variant }), className)}>
{children}
</span>
);
export type ButtonProps = ComponentPropsWithRef<"button"> & BaseButtonProps;

export const ButtonLabel = ({
variant = "primary",
size = "md",
className,
children,
}: ButtonSubProps) => (
<span className={cn(buttonLabelVariants({ variant, size }), className)}>
{children}
</span>
);
export type ButtonLabelProps = ButtonProps & {
label?: string;
};

export function Button({
variant = "primary",
size = "md",
export const Button = ({
variant = DEFAULT_BUTTON_PROPS.variant,
size = DEFAULT_BUTTON_PROPS.size,
disabled = false,
className,
children,
leftIcon,
rightIcon,
ref,
...props
}: ButtonProps) {
}: ButtonProps) => {
return (
<button
type="button"
disabled={disabled}
className={cn(ButtonVariants({ variant, size }), className)}
ref={ref}
{...props}
>
{leftIcon && (
<span className={cn(buttonIconVariants({ variant }))}>{leftIcon}</span>
)}
{children}
{rightIcon && (
<span className={cn(buttonIconVariants({ variant }))}>{rightIcon}</span>
)}
</button>
);
}
};

export const ButtonLabel = ({
label,
children,
variant = DEFAULT_BUTTON_PROPS.variant,
size = DEFAULT_BUTTON_PROPS.size,
ref,
...buttonProps
}: ButtonLabelProps) => {
return (
<Button variant={variant} size={size} ref={ref} {...buttonProps}>
{label && (
<span className={cn(buttonLabelVariants({ variant, size }))}>
{label}
</span>
)}
{children}
</Button>
);
};
15 changes: 13 additions & 2 deletions components/input/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { ComponentProps } from "react";
import clsx from "clsx";

export function Input({ className, ...props }: ComponentProps<"input">) {
type InputProps = ComponentProps<"input"> & {
inputRef?: React.Ref<HTMLInputElement>;
};

export function Input({ className, inputRef, ...props }: InputProps) {
return (
<input {...props} className={clsx("border rounded px-3 py-2", className)} />
<input
ref={inputRef}
{...props}
className={clsx(
"h-[54px] w-full rounded-[16px] border px-[20px] text-sm outline-none",
className
)}
/>
);
}
33 changes: 24 additions & 9 deletions components/input/inputfield.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
import { ReactNode } from "react";
import { Input } from "./Input";
import { useId, ReactNode } from "react";
import clsx from "clsx";
import { Input } from "./Input";

interface InputFieldProps {
interface InputFieldProps extends React.ComponentProps<typeof Input> {
label?: string;
error?: string;
helperText?: string;
inputProps?: React.ComponentProps<typeof Input>;
children?: ReactNode;
className?: string;
}

export function InputField({
label,
error,
helperText,
inputProps,
children,
className,
...props
}: InputFieldProps) {
const id = useId();

return (
<div className={clsx("flex flex-col gap-1", className)}>
{label && <label className="text-sm font-medium">{label}</label>}
<div className="flex w-full flex-col gap-[10px]">
{label && (
<label htmlFor={id} className="text-[16px] font-medium text-gray-900">
{label}
</label>
)}

{children ?? <Input {...inputProps} />}
{children ?? (
<Input
id={id}
{...props}
className={clsx(
error
? "border-red-500 focus:ring-red-500"
: "border-gray-200 focus:ring-primary-500",
className
)}
/>
)}

{error ? (
<p className="text-xs text-red-500">{error}</p>
Expand Down
15 changes: 8 additions & 7 deletions components/input/passwordinput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@ import { useState } from "react";
import Image from "next/image";
import { Input } from "./Input";
import type { ComponentProps } from "react";
import clsx from "clsx";

interface PasswordInputProps extends Omit<ComponentProps<"input">, "type"> {
className?: string;
}
type PasswordInputProps = ComponentProps<typeof Input>;

export function PasswordInput({ className, ...props }: PasswordInputProps) {
const [visible, setVisible] = useState(false);

return (
<div className="relative">
<div className="relative w-full">
<Input
{...props}
type={visible ? "text" : "password"}
className={`pr-10 ${className ?? ""}`}
className={clsx("pr-12", className)}
/>

<button
type="button"
aria-label={visible ? "비밀번호 숨기기" : "비밀번호 표시"}
aria-pressed={visible}
onClick={() => setVisible((v) => !v)}
className="absolute right-3 top-1/2 -translate-y-1/2"
className="absolute right-4 top-1/2 -translate-y-1/2 focus:outline-none focus:ring-2 focus:ring-primary-500"
>
<Image
src={visible ? "/icon_active_on.svg" : "/icon_active_off.svg"}
alt={visible ? "비밀번호 숨기기" : "비밀번호 보기"}
alt=""
width={20}
height={20}
/>
Expand Down
17 changes: 8 additions & 9 deletions components/input/searchinput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import Image from "next/image";
import { Input } from "./Input";
import type { ComponentProps } from "react";
import clsx from "clsx";

interface SearchInputProps extends ComponentProps<"input"> {
className?: string;
}

export function SearchInput({ className, ...props }: SearchInputProps) {
export function SearchInput({
className,
...props
}: ComponentProps<typeof Input>) {
return (
<div className="relative">
<Input {...props} className={`pl-10 ${className ?? ""}`} />

<span className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2">
<div className="relative w-full">
<Input {...props} className={clsx("pl-[44px]", className)} />
<span className="pointer-events-none absolute left-4 top-1/2 -translate-y-1/2">
<Image src="/icon_search.svg" alt="검색" width={20} height={20} />
</span>
</div>
Expand Down
Loading