Skip to content

Commit

Permalink
✨ feat: 주소 검색 인풋 컴포넌트 구현 및 스토리북 추가 #15
Browse files Browse the repository at this point in the history
  • Loading branch information
froggy1014 committed Aug 12, 2024
1 parent 22174f8 commit 0124d96
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/components/core/Input/AddressInput/AddressInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Meta, StoryObj } from "@storybook/react";

import AddressInput from "./AddressInput";

const meta: Meta<typeof AddressInput> = {
title: "Core/Input/AddressInput",
component: AddressInput,
parameters: {
layout: "centered",
},

argTypes: {
label: {
control: {
type: "text",
},
},
className: {
table: {
disable: true,
},
},
value: {
table: {
disable: true,
},
},
onChange: {
table: {
disable: true,
},
},
},
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: (args) => (
<div className="flex w-[360px] items-center justify-center">
<AddressInput {...args} />
</div>
),
args: {
label: "페스티벌 명",
},
};
102 changes: 102 additions & 0 deletions src/components/core/Input/AddressInput/AddressInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { FC, HtmlHTMLAttributes, useState } from "react";
import { Address, useDaumPostcodePopup } from "react-daum-postcode";

import { PinLocationIcon } from "@/components/icons";
import { cn } from "@/utils/cn";

interface Props
extends Omit<HtmlHTMLAttributes<HTMLButtonElement>, "onChange"> {
label?: string;
value: string | null;
className?: string;
onChange: (_address: string, _sido: string, _sigungu: string) => void;
}

const AddressInput: FC<Props> = ({
label = "페스티벌 장소",
value,
className,
onChange,
...props
}) => {
const [fullAddress, setFullAddress] = useState<string | null>(value);

const open = useDaumPostcodePopup(
"//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",
);

const getFullAddress = (address: Address) => {
let fullAddress = address.address;
let extraAddress = "";

if (address.addressType === "R") {
if (address.bname !== "") {
extraAddress += address.bname;
}
if (address.buildingName !== "") {
extraAddress +=
extraAddress !== ""
? `, ${address.buildingName}`
: address.buildingName;
}
fullAddress += extraAddress !== "" ? ` (${extraAddress})` : "";
}
return fullAddress;
};

const handleComplete = (data: Address) => {
const fullAddress = getFullAddress(data);
setFullAddress(fullAddress);

const { address, sido, sigungu } = data;
onChange(address, sido, sigungu);
};

const handleOpenAddressModal = () => {
open({
onComplete(address) {
handleComplete(address);
},
});
};

return (
<div className="flex w-full flex-col items-start gap-[8px]">
<label
htmlFor={label}
className="text-subtitle-medium text-gray-scale-900"
>
{label}
</label>
<button
type="button"
id={label}
onClick={handleOpenAddressModal}
className={cn(
"w-full rounded-[8px] p-[16px] bg-gray-scale-0 duration-300",
"border-[1px] border-gray-scale-200",
"placeholder:text-caption2-medium placeholder:text-gray-400 text-gray-scale-700",
"flex gap-[8px] justify-start items-center",
className,
)}
{...props}
>
<PinLocationIcon
width={16}
height={16}
className={!!fullAddress ? "text-primary-01" : "text-gray-400"}
/>
<span
className={cn(
"!text-caption2-medium max-w-[90%] text-ellipsis line-clamp-1",
!!fullAddress ? "text-gary-scale-700" : "text-gray-400",
)}
>
{!!fullAddress ? fullAddress : "페스티벌 개최 주소를 입력해주세요."}
</span>
</button>
</div>
);
};

export default AddressInput;

0 comments on commit 0124d96

Please sign in to comment.