Repository: WillYouMerryMe/getting-married
Pull request #32: feat(mobile): 참석자 관리 페이지 퍼블리싱
Author: login: junghongseop
Created: 2025-05-03T12:42:31Z | Merged: 2025-05-03T14:30:03Z

## 📄 Summary

> 참석자 관리 페이지를퍼블리싱 했습니다.

<br>

## 🔨 Tasks

- 검색 인풋 컴포넌트 개발
- 리스트 컴포넌트 개발
- 페이지 퍼블리싱
- 사용하는 아이콘 컴포넌트 추가
- Action Button 수정

<br>

## 🙋🏻 More

https://github.com/user-attachments/assets/9408d1d9-cace-48db-9c70-28cc24f13299



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **신규 기능**
	- 참석자 관리 페이지에 구조화된 UI와 참석자 목록 기능이 추가되었습니다.
	- 참석자 검색, 목록 헤더, 참석자별 상세 정보 표시, 참석자 추가 버튼이 제공됩니다.
	- 참석자 정보에는 이름, 소속(신랑/신부), 인원수, 참석 여부, 축의금, 식사 여부가 포함됩니다.
	- 검색 입력창과 새로운 아이콘(연필, 검색)이 도입되었습니다.

- **스타일**
	- 관리 페이지 및 버튼, 입력창, 목록 등에 새로운 스타일이 적용되었습니다.

- **버그 수정**
	- 없음

- **문서화**
	- 없음
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/mobile/src/app/manage/page.tsx b/apps/mobile/src/app/manage/page.tsx
index 4d9aa01d..6c521113 100644
--- a/apps/mobile/src/app/manage/page.tsx
+++ b/apps/mobile/src/app/manage/page.tsx
@@ -1,14 +1,39 @@
 'use client';
 
+import AttendeeList from '@/components/manage/AttendeeList/AttendeeList';
 import AppLayout from '@/layouts/AppLayout';
 import { color } from '@merried/design-system';
+import { ActionButton, Column, Text } from '@merried/ui';
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
 
 const Manage = () => {
   return (
-    <AppLayout footer backgroundColor={color.G20}>
-      참석자 관리 페이지
+    <AppLayout footer backgroundColor={color.G0}>
+      <StyledManage>
+        <Column gap={20}>
+          <Text fontType="H2" color={color.G900}>
+            참석자 관리
+          </Text>
+          <ActionButton icon="ADD_ICON" onClick={() => {}}>
+            참석자 추가
+          </ActionButton>
+        </Column>
+        <AttendeeList />
+      </StyledManage>
     </AppLayout>
   );
 };
 
 export default Manage;
+
+const StyledManage = styled.div`
+  ${flex({
+    flexDirection: 'column',
+    alignItems: 'flex-start',
+    justifyContent: 'flex-start',
+  })}
+  width: 100%;
+  gap: 24px;
+  padding: 71px 12px 115px;
+`;
diff --git a/apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx b/apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx
new file mode 100644
index 00000000..c24279c1
--- /dev/null
+++ b/apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx
@@ -0,0 +1,162 @@
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
+import SearchInput from '../SearchInput/SearchInput';
+import { Column, Text } from '@merried/ui';
+import ListHeader from './ListHeader/ListHeader';
+import { Side } from '@/types/manage/client';
+import ListItem from './ListItem/ListItem';
+import { color } from '@merried/design-system';
+import { useState } from 'react';
+
+export const listData: {
+  name: string;
+  side: Side;
+  count: number;
+  attend: boolean;
+  money: boolean;
+  meal: boolean;
+}[] = [
+  {
+    name: '홍길동',
+    side: 'GROOM',
+    count: 3,
+    attend: true,
+    money: true,
+    meal: false,
+  },
+  {
+    name: '홍이장군',
+    side: 'GROOM',
+    count: 3,
+    attend: true,
+    money: true,
+    meal: false,
+  },
+  {
+    name: '김영희',
+    side: 'BRIDE',
+    count: 2,
+    attend: true,
+    money: false,
+    meal: true,
+  },
+  {
+    name: '박철수',
+    side: 'GROOM',
+    count: 1,
+    attend: false,
+    money: false,
+    meal: false,
+  },
+  {
+    name: '이민호',
+    side: 'BRIDE',
+    count: 4,
+    attend: true,
+    money: true,
+    meal: true,
+  },
+  {
+    name: '최지우',
+    side: 'GROOM',
+    count: 2,
+    attend: false,
+    money: true,
+    meal: false,
+  },
+  {
+    name: '장보리',
+    side: 'BRIDE',
+    count: 5,
+    attend: true,
+    money: false,
+    meal: false,
+  },
+  {
+    name: '오세훈',
+    side: 'GROOM',
+    count: 1,
+    attend: false,
+    money: true,
+    meal: true,
+  },
+  {
+    name: '오세훈2',
+    side: 'GROOM',
+    count: 1,
+    attend: false,
+    money: true,
+    meal: true,
+  },
+];
+
+const AttendeeList = () => {
+  const [search, setSearch] = useState('');
+  const isEmpty = listData.length === 0;
+
+  const searchNameData = listData.filter((item) =>
+    item.name.toLowerCase().includes(search.toLowerCase())
+  );
+
+  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    setSearch(e.target.value);
+  };
+
+  return (
+    <StyledAttendeeList>
+      <Column gap={24} width="100%">
+        <SearchInput placeholder="이름을 입력해주세요" onChange={handleInputChange} />
+        {!isEmpty && <ListHeader />}
+      </Column>
+      <ListContainer>
+        <ListContent>
+          {isEmpty ? (
+            <EmptyContainer>
+              <Text fontType="H3_140per" color={color.G900} textAlign="center">
+                아직 참석 여부를
+                <br />
+                밝힌 사람이 없습니다
+              </Text>
+            </EmptyContainer>
+          ) : (
+            searchNameData.map((attendee, index) => (
+              <ListItem key={`attendee-${index}`} {...attendee} />
+            ))
+          )}
+        </ListContent>
+      </ListContainer>
+    </StyledAttendeeList>
+  );
+};
+
+export default AttendeeList;
+
+const StyledAttendeeList = styled.div`
+  ${flex({ flexDirection: 'column', alignItems: 'center' })}
+  width: 100%;
+  gap: 10px;
+`;
+
+const ListContainer = styled.div`
+  width: 100%;
+  height: calc(100vh - 450px);
+  overflow-y: auto;
+  -ms-overflow-style: none;
+  scrollbar-width: none;
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
+`;
+
+const ListContent = styled.div`
+  ${flex({ flexDirection: 'column', alignItems: 'center' })}
+  width: 100%;
+  gap: 10px;
+`;
+
+const EmptyContainer = styled.div`
+  ${flex({ flexDirection: 'column', alignItems: 'center', justifyContent: 'center' })}
+  width: 100%;
+  margin-top: 40%;
+`;
diff --git a/apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx b/apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx
new file mode 100644
index 00000000..987160e5
--- /dev/null
+++ b/apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx
@@ -0,0 +1,36 @@
+import { color } from '@merried/design-system';
+import { Row, Text } from '@merried/ui';
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
+
+const ListHeader = () => {
+  return (
+    <StyledListHeader>
+      <Text fontType="Button3" color={color.G80}>
+        이름
+      </Text>
+      <Row alignItems="center" gap={20}>
+        <Text fontType="Button3" color={color.G80}>
+          참석
+        </Text>
+        <Text fontType="Button3" color={color.G80}>
+          축의금
+        </Text>
+        <Text fontType="Button3" color={color.G80}>
+          식사
+        </Text>
+      </Row>
+    </StyledListHeader>
+  );
+};
+
+export default ListHeader;
+
+const StyledListHeader = styled.div`
+  ${flex({ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' })}
+  width: 100%;
+  height: 58px;
+  background-color: ${color.G10};
+  border-radius: 8px;
+  padding: 18px 16px;
+`;
diff --git a/apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx b/apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx
new file mode 100644
index 00000000..0904c562
--- /dev/null
+++ b/apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx
@@ -0,0 +1,65 @@
+import { SIDE } from '@/constants/common/constant';
+import { Side } from '@/types/manage/client';
+import { color } from '@merried/design-system';
+import { IconPencil } from '@merried/icon';
+import { Column, Row, Text } from '@merried/ui';
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
+
+interface ListItemProps {
+  name: string;
+  side: Side;
+  count: number;
+  attend: boolean;
+  money: boolean;
+  meal: boolean;
+}
+
+const ListItem = ({ name, side, count, attend, money, meal }: ListItemProps) => {
+  return (
+    <StyledListItem onClick={() => {}}>
+      <Row alignItems="center" gap={10}>
+        <IconPencil width={16} height={16} />
+        <Column alignItems="flex-start">
+          <Text fontType="P3" color={color.G900}>
+            {name}
+          </Text>
+          <Row alignItems="center" gap={4}>
+            <Text fontType="P3" color={color.G70}>
+              {SIDE[side]}측
+            </Text>
+            <Text fontType="P3" color={color.G70}>
+              •
+            </Text>
+            <Text fontType="P3" color={color.G70}>
+              본인 포함 {count}명
+            </Text>
+          </Row>
+        </Column>
+      </Row>
+      <Row alignItems="center" justifyContent="space-between" width={127}>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {attend === true ? 'O' : 'X'}
+        </Text>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {money === true ? 'O' : 'X'}
+        </Text>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {meal === true ? 'O' : 'X'}
+        </Text>
+      </Row>
+    </StyledListItem>
+  );
+};
+
+export default ListItem;
+
+const StyledListItem = styled.div`
+  ${flex({ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' })}
+  width: 100%;
+  height: 68px;
+  background-color: ${color.G0};
+  border: 1px solid ${color.G40};
+  border-radius: 8px;
+  padding: 18px 16px;
+`;
diff --git a/apps/mobile/src/components/manage/SearchInput/SearchInput.tsx b/apps/mobile/src/components/manage/SearchInput/SearchInput.tsx
new file mode 100644
index 00000000..fe0a8bc3
--- /dev/null
+++ b/apps/mobile/src/components/manage/SearchInput/SearchInput.tsx
@@ -0,0 +1,65 @@
+import { color, font } from '@merried/design-system';
+import { IconSearch } from '@merried/icon';
+import { flex } from '@merried/utils';
+import { CSSProperties, InputHTMLAttributes, useRef } from 'react';
+import styled from 'styled-components';
+
+export interface SearchInputProps extends InputHTMLAttributes<HTMLInputElement> {
+  width?: CSSProperties['width'];
+}
+
+const SearchInput = ({
+  width,
+  onChange,
+  value,
+  name,
+  placeholder,
+  type = 'text',
+}: SearchInputProps) => {
+  const inputRef = useRef<HTMLInputElement>(null);
+
+  const handleClick = () => {
+    inputRef.current?.focus();
+  };
+
+  return (
+    <StyledSearchInput onClick={handleClick} style={{ width }}>
+      <Input
+        ref={inputRef}
+        placeholder={placeholder}
+        onChange={onChange}
+        value={value}
+        name={name}
+        type={type}
+      />
+      <IconSearch width={16} height={16} />
+    </StyledSearchInput>
+  );
+};
+
+export default SearchInput;
+
+const StyledSearchInput = styled.div`
+  ${flex({ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' })}
+  width: 100%;
+  height: 44px;
+  border-radius: 8px;
+  background-color: ${color.G10};
+  padding: 14px 16px;
+`;
+
+const Input = styled.input`
+  width: 90%;
+  background-color: ${color.G10};
+  ${font.P3}
+
+  ::placeholder {
+    ${font.P3}
+    color: ${color.G60};
+  }
+
+  &::-webkit-input-placeholder {
+    ${font.P3}
+    color: ${color.G60};
+  }
+`;
diff --git a/apps/mobile/src/constants/common/constant.ts b/apps/mobile/src/constants/common/constant.ts
index 6f1f0f63..eec5f408 100644
--- a/apps/mobile/src/constants/common/constant.ts
+++ b/apps/mobile/src/constants/common/constant.ts
@@ -1,3 +1,5 @@
+import { Side } from '@/types/manage/client';
+
 export const ROUTES = {
   LOGIN: '/',
   HOME: '/home',
@@ -5,3 +7,8 @@ export const ROUTES = {
   SHOP: '/shop',
   MY: '/my',
 };
+
+export const SIDE: Record<Side, string> = {
+  GROOM: '신랑',
+  BRIDE: '신부',
+};
diff --git a/apps/mobile/src/types/manage/client.ts b/apps/mobile/src/types/manage/client.ts
new file mode 100644
index 00000000..84cf917b
--- /dev/null
+++ b/apps/mobile/src/types/manage/client.ts
@@ -0,0 +1 @@
+export type Side = 'GROOM' | 'BRIDE';
diff --git a/packages/icon/index.ts b/packages/icon/index.ts
index 8b71c6a0..97b69001 100644
--- a/packages/icon/index.ts
+++ b/packages/icon/index.ts
@@ -11,3 +11,5 @@ export { default as IconProfile } from './src/IconProfile';
 export { default as IconFolder } from './src/IconFolder';
 export { default as IconBoldShare } from './src/IconBoldShare';
 export { default as IconBoldLetter } from './src/IconBoldLetter';
+export { default as IconSearch } from './src/IconSearch';
+export { default as IconPencil } from './src/IconPencil';
diff --git a/packages/icon/src/IconPencil.tsx b/packages/icon/src/IconPencil.tsx
new file mode 100644
index 00000000..d8232e94
--- /dev/null
+++ b/packages/icon/src/IconPencil.tsx
@@ -0,0 +1,36 @@
+import type { SVGProps } from 'react';
+import React from 'react';
+
+const IconPencil = (props: SVGProps<SVGSVGElement>) => (
+  <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
+    <g clipPath="url(#clip0_869_3921)">
+      <path opacity="0.36" d="M16 0H0V16H16V0Z" fill="white" />
+      <path
+        d="M4.81038 14.6663H1.33301V11.189L10.7845 1.73748C11.0451 1.47842 11.3976 1.33301 11.7651 1.33301C12.1326 1.33301 12.4851 1.47842 12.7457 1.73748L14.2619 3.25362C14.5209 3.51423 14.6663 3.86677 14.6663 4.23424C14.6663 4.6017 14.5209 4.95424 14.2619 5.21485L4.81038 14.6663Z"
+        stroke="#FFC0CF"
+        strokeWidth="2"
+        strokeLinecap="round"
+      />
+      <path
+        d="M4.81038 14.6668L1.33301 11.1895V14.6668H4.81038Z"
+        stroke="#FFC0CF"
+        strokeWidth="2"
+        strokeLinecap="round"
+        strokeLinejoin="round"
+      />
+      <path
+        d="M9.67871 2.84329L13.1561 6.32066L14.2619 5.21485C14.5209 4.95424 14.6664 4.6017 14.6664 4.23424C14.6664 3.86677 14.5209 3.51423 14.2619 3.25362L12.7458 1.73748C12.4851 1.47842 12.1326 1.33301 11.7651 1.33301C11.3977 1.33301 11.0451 1.47842 10.7845 1.73748L9.67871 2.84329Z"
+        stroke="#FFC0CF"
+        strokeWidth="2"
+        strokeLinecap="round"
+      />
+    </g>
+    <defs>
+      <clipPath id="clip0_869_3921">
+        <rect width="16" height="16" fill="white" />
+      </clipPath>
+    </defs>
+  </svg>
+);
+
+export default IconPencil;
diff --git a/packages/icon/src/IconSearch.tsx b/packages/icon/src/IconSearch.tsx
new file mode 100644
index 00000000..e739a5f9
--- /dev/null
+++ b/packages/icon/src/IconSearch.tsx
@@ -0,0 +1,29 @@
+import type { SVGProps } from 'react';
+import React from 'react';
+
+const IconSearch = (props: SVGProps<SVGSVGElement>) => (
+  <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
+    <g clipPath="url(#clip0_1263_3881)">
+      <path
+        d="M6.66732 11.9997C9.61284 11.9997 12.0007 9.61186 12.0007 6.66634C12.0007 3.72082 9.61284 1.33301 6.66732 1.33301C3.7218 1.33301 1.33398 3.72082 1.33398 6.66634C1.33398 9.61186 3.7218 11.9997 6.66732 11.9997Z"
+        stroke="#FFC0CF"
+        strokeWidth="2"
+        strokeMiterlimit="10"
+      />
+      <path
+        d="M14.666 14.667L10.666 10.667"
+        stroke="#FFC0CF"
+        strokeWidth="2"
+        strokeLinecap="square"
+        strokeLinejoin="round"
+      />
+    </g>
+    <defs>
+      <clipPath id="clip0_1263_3881">
+        <rect width="16" height="16" fill="white" />
+      </clipPath>
+    </defs>
+  </svg>
+);
+
+export default IconSearch;
diff --git a/packages/ui/src/Button/ActionButton.tsx b/packages/ui/src/Button/ActionButton.tsx
index 6142a9f5..4f888e8b 100644
--- a/packages/ui/src/Button/ActionButton.tsx
+++ b/packages/ui/src/Button/ActionButton.tsx
@@ -1,14 +1,15 @@
 import { ButtonHTMLAttributes, ReactNode, CSSProperties } from 'react';
 import { ButtonIcon } from './button.type';
 import styled from 'styled-components';
-import { flex } from '@merried/utils';
 import { color } from '@merried/design-system';
 import { IconAdd } from '@merried/icon';
+import Text from '../Text/Text';
 
 type Props = {
   children: ReactNode;
   icon?: ButtonIcon;
   width?: CSSProperties['width'];
+  background?: string;
 } & ButtonHTMLAttributes<HTMLButtonElement>;
 
 const ActionButton = ({
@@ -18,22 +19,30 @@ const ActionButton = ({
   icon = 'NONE',
   style,
   disabled,
+  background = color.primary,
 }: Props) => {
   return (
-    <StyledActionButton style={{ width, ...style }} onClick={onClick} disabled={disabled}>
+    <StyledActionButton
+      style={{ width, ...style }}
+      onClick={onClick}
+      disabled={disabled}
+      background={background}
+    >
       {icon === 'ADD_ICON' && <IconAdd color={color.G0} width={12} height={12} />}
-      {children}
+      <Text fontType="Button3" color={color.G0}>
+        {children}
+      </Text>
     </StyledActionButton>
   );
 };
 
 export default ActionButton;
 
-const StyledActionButton = styled.button`
+const StyledActionButton = styled.button<{ background: string }>`
   display: inline-flex;
   align-items: center;
   justify-content: center;
-  background-color: ${color.primary};
+  background-color: ${(props) => props.background};
   gap: 8px;
   border-radius: 999px;
   height: 34px;


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🧹 Nitpick comments (15)</summary><blockquote>

<details>
<summary>packages/icon/src/IconSearch.tsx (1)</summary><blockquote>

`1-30`: **아이콘 컴포넌트 구현 확인 및 접근성 제안**  
SVG로 잘 구현해주셨고, `SVGProps`를 그대로 받아 확장성도 좋네요.  
다만, 이 아이콘이 순수 장식용이라면 `aria-hidden="true"`를 기본으로 추가하거나 props로 `role="img"`/`aria-label`을 전달할 수 있게 하면 스크린 리더 이용자에게 더 친절해질 거예요.

</blockquote></details>
<details>
<summary>packages/icon/src/IconPencil.tsx (1)</summary><blockquote>

`1-37`: **아이콘 컴포넌트 구현 확인 및 접근성 제안**  
펜슬 아이콘도 `SVGProps`를 잘 활용해 크기, 색상 등을 쉽게 조정할 수 있네요.  
앞서 제안드린 것처럼, 이 컴포넌트 역시 기본 `aria-hidden="true"` 또는 `role`/`aria-label` 옵션을 제공하면 더욱 접근성 친화적일 거예요.

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx (1)</summary><blockquote>

`6-25`: **컴포넌트 구조가 잘 설계되었어요**

리스트 헤더 컴포넌트가 아주 깔끔하게 구성되어 있어요. 행과 텍스트를 사용해서 참석자 목록의 헤더를 예쁘게 만들었네요! 

하지만 한 가지 조그만 개선점을 제안해 볼게요. 접근성을 위해 이 헤더에 의미적인 역할을 부여해 주면 더 좋을 것 같아요. 다음과 같이 HTML5 시맨틱 요소나 ARIA 속성을 추가하는 것을 고려해 보세요:

```diff
- <StyledListHeader>
+ <StyledListHeader role="rowheader" aria-label="참석자 목록 헤더">
```

이렇게 하면 스크린 리더를 사용하는 사람들에게도 이 요소의 목적이 명확하게 전달될 수 있어요! 🌈

</blockquote></details>
<details>
<summary>packages/ui/src/Button/ActionButton.tsx (2)</summary><blockquote>

`25-35`: **버튼 내용을 Text 컴포넌트로 감싼 것이 좋아요**

버튼의 텍스트를 Text 컴포넌트로 감싸서 일관된 스타일을 적용한 것이 아주 좋은 변화예요! 이렇게 하면 디자인 시스템의 타이포그래피 규칙을 잘 따를 수 있고, 스타일 관리도 더 쉬워져요.

다만, 버튼이 비활성화(disabled)되었을 때 텍스트 색상도 함께 변경되면 좋을 것 같아요. 현재는 버튼이 비활성화되어도 텍스트 색상은 항상 G0로 고정되어 있어요. 다음과 같이 조건부 스타일링을 추가하는 건 어떨까요?

```diff
- <Text fontType="Button3" color={color.G0}>
+ <Text fontType="Button3" color={disabled ? color.G40 : color.G0}>
```

이렇게 하면 버튼이 비활성화되었을 때 시각적으로도 더 명확하게 구분할 수 있어요! 😊

---

`41-51`: **스타일드 컴포넌트에 background props를 추가한 것이 좋아요**

StyledActionButton에 background props를 추가해서 배경색을 동적으로 설정할 수 있게 한 것이 아주 좋아요! 이렇게 하면 다양한 상황에 맞게 버튼 색상을 변경할 수 있어요.

작은 개선점을 제안해 볼게요. 버튼에 마우스를 올렸을 때나 클릭했을 때의 상태(hover, active)에 대한 스타일링이 없어요. 사용자 경험을 더 좋게 만들기 위해 이런 상태에 대한 스타일을 추가하면 어떨까요?

```diff
const StyledActionButton = styled.button<{ background: string }>`
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: ${(props) => props.background};
  gap: 8px;
  border-radius: 999px;
  height: 34px;
  padding: 10px 24px;
  word-break: keep-all;
+ transition: opacity 0.2s ease;
+
+ &:hover {
+   opacity: 0.9;
+ }
+
+ &:active {
+   opacity: 0.8;
+ }
+
+ &:disabled {
+   opacity: 0.5;
+   cursor: not-allowed;
+ }
`;
```

이렇게 하면 버튼과 상호작용할 때 시각적 피드백이 생겨서 사용자 경험이 더 좋아질 거예요! 🎨

</blockquote></details>
<details>
<summary>apps/mobile/src/app/manage/page.tsx (1)</summary><blockquote>

`30-39`: **StyledManage 컴포넌트가 잘 스타일링되었어요**

StyledManage 컴포넌트의 스타일링이 아주 깔끔하고 체계적이에요! flex 유틸리티를 사용해 요소들의 배치를 잘 조정했고, 적절한 여백과 패딩을 설정했네요.

다만, 패딩 값이 고정되어 있어서(71px 12px 115px) 다양한 화면 크기에 대응하기 어려울 수 있어요. 모바일 환경에 최적화된 값이겠지만, 혹시 다양한 디바이스에 대응해야 한다면 상대적인 값을 사용하거나 미디어 쿼리를 추가하는 것도 고려해보세요:

```diff
- padding: 71px 12px 115px;
+ padding: 10vh 12px 15vh;  // 화면 높이에 따라 상대적인 값을 사용
```

또는

```diff
padding: 71px 12px 115px;

+ @media (max-height: 600px) {
+   padding: 40px 12px 60px;
+ }
```

이렇게 하면 다양한 화면 크기에서도 예쁘게 보일 수 있어요! 📱✨

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx (2)</summary><blockquote>

`9-16`: **인터페이스 정의가 명확해요**

`ListItemProps` 인터페이스가 아주 명확하게 정의되어 있어요! 각 속성의 타입이 잘 지정되어 있고, 필요한 모든 정보가 포함되어 있네요.

작은 개선점을 제안해 볼게요. 몇몇 props에는 기본값이 있으면 좋을 것 같아요. 예를 들어, `attend`, `money`, `meal`은 기본적으로 `false`로 설정되면 어떨까요? 이렇게 하면 컴포넌트를 사용할 때 모든 값을 매번 지정하지 않아도 돼요:

```diff
interface ListItemProps {
  name: string;
  side: Side;
  count: number;
-  attend: boolean;
-  money: boolean;
-  meal: boolean;
+  attend?: boolean;
+  money?: boolean;
+  meal?: boolean;
}
```

그리고 컴포넌트에서 기본값을 설정해줄 수 있어요:

```diff
-const ListItem = ({ name, side, count, attend, money, meal }: ListItemProps) => {
+const ListItem = ({ name, side, count, attend = false, money = false, meal = false }: ListItemProps) => {
```

이렇게 하면 컴포넌트를 더 유연하게 사용할 수 있어요! 😊

---

`57-65`: **스타일 컴포넌트가 잘 정의되었어요**

`StyledListItem`의 스타일링이 아주 깔끔하고 일관되게 정의되어 있어요! flex 유틸리티를 사용해 레이아웃을 설정하고, 적절한 크기와 색상, 테두리, 그리고 패딩을 지정했네요.

작은 제안을 드리자면, 이 컴포넌트는 클릭 가능한 요소인 것 같은데 hover나 active 상태에 대한 스타일링이 없어요. 사용자에게 더 좋은 경험을 제공하기 위해 이런 상태에 대한 스타일을 추가하면 어떨까요?

```diff
const StyledListItem = styled.div`
  ${flex({ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' })}
  width: 100%;
  height: 68px;
  background-color: ${color.G0};
  border: 1px solid ${color.G40};
  border-radius: 8px;
  padding: 18px 16px;
+  cursor: pointer;
+  transition: border-color 0.2s ease, box-shadow 0.2s ease;
+
+  &:hover {
+    border-color: ${color.G50};
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+  }
+
+  &:active {
+    border-color: ${color.G60};
+    background-color: ${color.G10};
+  }
`;
```

이렇게 하면 사용자가 아이템과 상호작용할 때 시각적 피드백을 받을 수 있어 더 좋은 경험을 제공할 수 있어요! 😊

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx (5)</summary><blockquote>

`1-10`: **임포트 구조가 잘 정리되어 있어요! 👍**

컴포넌트에 필요한 모든 모듈을 잘 임포트해왔네요. 하지만 임포트 순서를 조금 더 체계적으로 정리하면 코드를 읽는 사람이 더 쉽게 이해할 수 있을 것 같아요.

다음과 같은 순서로 정리해보는 건 어떨까요?
1. React 관련 임포트 (useState)
2. 외부 라이브러리 (styled-components)
3. 내부 컴포넌트
4. 디자인 시스템 요소
5. 타입과 유틸리티


```diff
+import { useState } from 'react';
+import styled from 'styled-components';
+import { Column, Text } from '@merried/ui';
+import { color } from '@merried/design-system';
+import { flex } from '@merried/utils';
+import SearchInput from '../SearchInput/SearchInput';
+import ListHeader from './ListHeader/ListHeader';
+import ListItem from './ListItem/ListItem';
+import { Side } from '@/types/manage/client';
-import { flex } from '@merried/utils';
-import styled from 'styled-components';
-import SearchInput from '../SearchInput/SearchInput';
-import { Column, Text } from '@merried/ui';
-import ListHeader from './ListHeader/ListHeader';
-import { Side } from '@/types/manage/client';
-import ListItem from './ListItem/ListItem';
-import { color } from '@merried/design-system';
-import { useState } from 'react';
```

---

`11-91`: **샘플 데이터를 별도의 파일로 분리하면 더 좋을 것 같아요! 📁**

지금은 컴포넌트 파일 안에 샘플 데이터를 직접 넣어두셨는데요, 이 방식은 컴포넌트 파일이 너무 길어지고 복잡해 보일 수 있어요. 데이터를 별도의 파일로 분리하면 코드를 더 깔끔하게 관리할 수 있답니다.

나중에 실제 API와 연결할 때도 코드 수정이 더 쉬워질 거예요! 또한 배열에 타입을 명시적으로 지정해주면 더 좋을 것 같아요.


```diff
-export const listData: {
-  name: string;
-  side: Side;
-  count: number;
-  attend: boolean;
-  money: boolean;
-  meal: boolean;
-}[] = [
```

다음과 같이 별도의 파일로 분리해보세요:

```typescript
// apps/mobile/src/mocks/attendeeData.ts
import { Side } from '@/types/manage/client';

export interface Attendee {
  name: string;
  side: Side;
  count: number;
  attend: boolean;
  money: boolean;
  meal: boolean;
}

export const listData: Attendee[] = [
  {
    name: '홍길동',
    side: 'GROOM',
    count: 3,
    attend: true,
    money: true,
    meal: false,
  },
  // 나머지 데이터...
];
```

그리고 컴포넌트에서는 이렇게 불러와서 사용하면 돼요:

```typescript
import { listData, Attendee } from '@/mocks/attendeeData';
```

---

`93-104`: **검색 기능이 잘 구현되어 있어요! 🔍**

검색 상태 관리와 필터링 로직이 깔끔하게 잘 작성되었네요. 다만, 검색어가 빈 문자열일 때의 처리를 명시적으로 해주면 더 좋을 것 같아요.


```diff
const AttendeeList = () => {
  const [search, setSearch] = useState('');
  const isEmpty = listData.length === 0;

-  const searchNameData = listData.filter((item) =>
-    item.name.toLowerCase().includes(search.toLowerCase())
-  );
+  const searchNameData = search.trim() === '' 
+    ? listData 
+    : listData.filter((item) =>
+        item.name.toLowerCase().includes(search.toLowerCase().trim())
+      );

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearch(e.target.value);
  };
```

이렇게 하면 검색어가 비어있을 때는 모든 데이터를 보여주고, 검색어의 앞뒤 공백도 제거해서 검색이 더 정확해질 거예요! 😊

---

`105-130`: **컴포넌트 구조와 조건부 렌더링이 잘 되어 있어요! ✨**

컴포넌트의 구조가 깔끔하고, 빈 목록일 때와 아닐 때의 조건부 렌더링도 잘 구현되었어요. 다만, 목록 아이템의 키(key)를 인덱스와 함께 사용하는 것보다 고유한 값을 사용하는 것이 더 좋아요.


```diff
{searchNameData.map((attendee, index) => (
-  <ListItem key={`attendee-${index}`} {...attendee} />
+  <ListItem key={`${attendee.name}-${attendee.side}-${index}`} {...attendee} />
))}
```

또한, 목록이 비어있을 때 표시되는 메시지에 접근성을 높이기 위한 ARIA 속성을 추가하면 좋을 것 같아요:

```diff
<EmptyContainer>
-  <Text fontType="H3_140per" color={color.G900} textAlign="center">
+  <Text 
+    fontType="H3_140per" 
+    color={color.G900} 
+    textAlign="center"
+    aria-live="polite"
+    role="status"
+  >
    아직 참석 여부를
    <br />
    밝힌 사람이 없습니다
  </Text>
</EmptyContainer>
```

이렇게 하면 스크린 리더와 같은 보조 기술을 사용하는 사용자들에게도 친화적인 인터페이스가 될 거예요! 💖

---

`134-162`: **스타일 컴포넌트가 잘 구성되어 있어요! 🎨**

스타일 컴포넌트들이 기능별로 잘 분리되어 있고, flex 유틸리티를 활용한 레이아웃 구성도 깔끔해요. 다만, `ListContainer`의 높이를 고정값으로 계산하는 부분은 다양한 화면 크기에 대응하기 어려울 수 있어요.


```diff
const ListContainer = styled.div`
  width: 100%;
-  height: calc(100vh - 450px);
+  max-height: calc(100vh - 450px);
+  min-height: 300px;
  overflow-y: auto;
  -ms-overflow-style: none;
  scrollbar-width: none;

  &::-webkit-scrollbar {
    display: none;
  }
`;
```

또한, `EmptyContainer`의 마진 값도 상대적인 값으로 변경하면 더 반응형에 가까워질 거예요:

```diff
const EmptyContainer = styled.div`
  ${flex({ flexDirection: 'column', alignItems: 'center', justifyContent: 'center' })}
  width: 100%;
-  margin-top: 40%;
+  padding: 2rem 0;
+  flex-grow: 1;
+  display: flex;
+  align-items: center;
`;
```

이렇게 하면 작은 화면에서도 빈 상태 메시지가 적절하게 표시될 거예요! 📱✨

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/SearchInput/SearchInput.tsx (2)</summary><blockquote>

`1-10`: **임포트와 인터페이스 정의가 깔끔해요! 📚**

필요한 모듈들을 잘 임포트해오셨네요. 인터페이스 정의도 HTML 입력 속성을 확장해서 width 속성을 추가한 점이 훌륭해요. 컴포넌트의 재사용성을 높이는 좋은 접근 방식이에요!

다만, 임포트 구문의 순서를 조금 정리하면 더 읽기 좋을 것 같아요:


```diff
+import { CSSProperties, InputHTMLAttributes, useRef } from 'react';
+import styled from 'styled-components';
+import { color, font } from '@merried/design-system';
+import { IconSearch } from '@merried/icon';
+import { flex } from '@merried/utils';
-import { color, font } from '@merried/design-system';
-import { IconSearch } from '@merried/icon';
-import { flex } from '@merried/utils';
-import { CSSProperties, InputHTMLAttributes, useRef } from 'react';
-import styled from 'styled-components';
```

이렇게 React 관련 임포트를 먼저, 그 다음 외부 라이브러리, 마지막으로 내부 모듈 순서로 정리하면 코드를 읽는 사람이 더 쉽게 이해할 수 있어요! 😊

---

`41-64`: **스타일링이 잘 되어 있지만, 몇 가지 개선할 점이 있어요! 🎨**

스타일드 컴포넌트로 입력 필드와 컨테이너를 스타일링한 방식이 깔끔해요. 특히 플레이스홀더 스타일을 브라우저별로 대응한 점이 훌륭해요!

다만, 입력 필드의 너비를 고정 비율(90%)로 설정한 것은 아이콘 크기가 변경될 경우 문제가 될 수 있어요. flex-grow를 사용하면 더 유연하게 대응할 수 있을 거예요:


```diff
const Input = styled.input`
-  width: 90%;
+  flex: 1;
+  margin-right: 10px;
  background-color: ${color.G10};
  ${font.P3}
```

또한, 포커스 상태일 때의 스타일을 추가하면 사용자 경험이 더 좋아질 거예요:

```diff
const Input = styled.input`
  flex: 1;
  margin-right: 10px;
  background-color: ${color.G10};
  ${font.P3}
+  outline: none;
+
+  &:focus {
+    caret-color: ${color.primary};
+  }

  ::placeholder {
```

그리고 접근성을 높이기 위해 Input 컴포넌트에 border를 추가하고, 포커스 시 시각적 표시를 명확히 하는 것도 좋을 것 같아요:

```diff
const StyledSearchInput = styled.div`
  ${flex({ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' })}
  width: 100%;
  height: 44px;
  border-radius: 8px;
  background-color: ${color.G10};
  padding: 14px 16px;
+  border: 1px solid transparent;
+  transition: border-color 0.2s ease;
+
+  &:focus-within {
+    border-color: ${color.primary};
+  }
`;
```

이렇게 하면 사용자가 입력 필드에 포커스했을 때 시각적으로 더 명확하게 알 수 있어 사용성이 향상될 거예요! 👀✨

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between dc9563f6f945e1d3f49bcd3d91b665dd289b017a and 07bd822250f6dd5b6104ddbeac1518e64a02a911.

</details>

<details>
<summary>📒 Files selected for processing (11)</summary>

* `apps/mobile/src/app/manage/page.tsx` (1 hunks)
* `apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx` (1 hunks)
* `apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx` (1 hunks)
* `apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx` (1 hunks)
* `apps/mobile/src/components/manage/SearchInput/SearchInput.tsx` (1 hunks)
* `apps/mobile/src/types/manage/client.ts` (1 hunks)
* `apps/mobile/src/utils/formatSide.ts` (1 hunks)
* `packages/icon/index.ts` (1 hunks)
* `packages/icon/src/IconPencil.tsx` (1 hunks)
* `packages/icon/src/IconSearch.tsx` (1 hunks)
* `packages/ui/src/Button/ActionButton.tsx` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>apps/mobile/src/utils/formatSide.ts (1)</summary><blockquote>

<details>
<summary>apps/mobile/src/types/manage/client.ts (1)</summary>

* `Side` (1-1)

</details>

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx (2)</summary><blockquote>

<details>
<summary>apps/mobile/src/types/manage/client.ts (1)</summary>

* `Side` (1-1)

</details>
<details>
<summary>apps/mobile/src/utils/formatSide.ts (1)</summary>

* `formatSide` (3-6)

</details>

</blockquote></details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx (1)</summary><blockquote>

<details>
<summary>apps/mobile/src/types/manage/client.ts (1)</summary>

* `Side` (1-1)

</details>

</blockquote></details>
<details>
<summary>packages/ui/src/Button/ActionButton.tsx (1)</summary><blockquote>

<details>
<summary>packages/ui/src/Button/button.type.ts (1)</summary>

* `ButtonIcon` (7-7)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>apps/mobile/src/types/manage/client.ts (1)</summary>

`1-1`: **새로운 타입 정의 확인!**  
`Side` 타입을 `'GROOM' | 'BRIDE'`로 깔끔하게 정의해주셨네요. 이 설정은 참석자의 양측(신랑/신부)을 엄격하게 타입체크할 수 있어서, 컴포넌트 전반에 걸친 일관성을 유지하는 데 큰 도움이 될 거예요.

</details>
<details>
<summary>packages/icon/index.ts (1)</summary>

`14-15`: **아이콘 컴포넌트 추가 확인!**  
`IconSearch`와 `IconPencil`을 패키지 인덱스에 잘 등록해주셨네요. 이렇게 하면 이 두 아이콘을 다른 컴포넌트에서 쉽게 불러다 쓸 수 있어요.

</details>
<details>
<summary>apps/mobile/src/utils/formatSide.ts (1)</summary>

`1-6`: **측면(side) 포맷 매핑 유틸 확정!**  
`Side` 타입을 import해서 `Record<Side, string>` 형태로 한눈에 볼 수 있게 잘 정리해주셨네요. 이러면 `GROOM`과 `BRIDE`를 사용할 때 오타 걱정 없이 `'신랑'/'신부'`로 변환할 수 있어요.

</details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/ListHeader/ListHeader.tsx (2)</summary>

`1-5`: **임포트 구성이 깔끔하게 되어 있어요!**

디자인 시스템, UI 컴포넌트, 유틸리티를 잘 가져와서 사용하고 있네요. 깔끔한 코드 구성이랍니다! 🌟

---

`29-36`: **스타일 컴포넌트가 잘 정의되었어요**

`StyledListHeader`의 스타일링이 아주 일관되고 깔끔해요! flex 유틸리티를 사용해서 레이아웃을 잘 구성했고, 색상과 크기도 적절하게 지정했네요.

작은 제안을 드리자면, 나중에 반응형 디자인을 고려한다면 고정된 높이(58px)와 패딩 값을 미디어 쿼리를 사용해 다양한 화면 크기에 맞게 조정할 수 있을 것 같아요. 하지만 현재 모바일 환경에 집중한다면 지금처럼 고정값을 사용하는 것도 괜찮아요! 😊

</details>
<details>
<summary>packages/ui/src/Button/ActionButton.tsx (1)</summary>

`6-6`: **Text 컴포넌트를 가져오는 것 좋아요!**

Text 컴포넌트를 임포트해서 버튼 내용의 스타일을 일관되게 관리하려는 접근이 아주 좋아요! 이렇게 하면 디자인 시스템의 타이포그래피 규칙을 버튼 내에서도 잘 지킬 수 있어요. 👍

</details>
<details>
<summary>apps/mobile/src/app/manage/page.tsx (1)</summary>

`3-8`: **필요한 컴포넌트와 스타일을 잘 가져왔어요**

AttendeeList, AppLayout, 그리고 다양한 디자인 시스템 요소들을 잘 가져왔네요! 임포트 구문이 깔끔하게 정리되어 있어 코드를 이해하기 쉬워요. 🌟

</details>
<details>
<summary>apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx (1)</summary>

`1-8`: **필요한 타입과 유틸리티를 잘 가져왔어요**

필요한 타입(`Side`)과 유틸리티(`formatSide`), 그리고 UI 컴포넌트들을 잘 가져왔어요! 임포트 구문이 체계적으로 정리되어 있어 코드를 이해하기 쉽네요. 🌟

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-03T12:45:48Z
user: login: MinjuN07
body: 수고하셨습니다. 영상으로 보니까 예쁘네요!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T14:27:06Z
user: login: junghongseop
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-03T14:27:47Z

Review comments:
diff_hunk: @@ -1,14 +1,15 @@
 import { ButtonHTMLAttributes, ReactNode, CSSProperties } from 'react';
 import { ButtonIcon } from './button.type';
 import styled from 'styled-components';
-import { flex } from '@merried/utils';
 import { color } from '@merried/design-system';
 import { IconAdd } from '@merried/icon';
+import Text from '../Text/Text';
 
 type Props = {
   children: ReactNode;
   icon?: ButtonIcon;
   width?: CSSProperties['width'];
+  background: string;
 } & ButtonHTMLAttributes<HTMLButtonElement>;
path: packages/ui/src/Button/ActionButton.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Props 타입에 background를 필수로 추가했네요**

background 속성을 필수 props로 추가한 것이 보이네요! 버튼의 배경색을 동적으로 지정할 수 있게 되었어요.

하지만 작은 개선점을 제안해 볼게요. background를 필수값으로 만들었기 때문에, 기존 코드에서 이 컴포넌트를 사용하는 모든 곳에서 이 속성을 추가해야 해요. 혹시 기본값을 제공하는 건 어떨까요? 이렇게 하면 기존 코드의 호환성도 유지할 수 있어요:

```diff
- background: string;
+ background?: string;
```

그리고 컴포넌트 내에서 기본값을 설정할 수 있어요:

```diff
- background,
+ background = color.primary,
```

이렇게 하면 배경색을 지정하지 않아도 기본 색상이 적용되어 더 유연하게 사용할 수 있어요! 🌈



> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-03T12:45:46Z
author_association: NONE
diff_hunk: @@ -1,14 +1,39 @@
 'use client';
 
+import AttendeeList from '@/components/manage/AttendeeList/AttendeeList';
 import AppLayout from '@/layouts/AppLayout';
 import { color } from '@merried/design-system';
+import { ActionButton, Column, Text } from '@merried/ui';
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
 
 const Manage = () => {
   return (
-    <AppLayout footer backgroundColor={color.G20}>
-      참석자 관리 페이지
+    <AppLayout footer backgroundColor={color.G0}>
+      <StyledManage>
+        <Column gap={20}>
+          <Text fontType="H2" color={color.G900}>
+            참석자 관리
+          </Text>
+          <ActionButton icon="ADD_ICON" background={color.primary} onClick={() => {}}>
+            참석자 추가
+          </ActionButton>
+        </Column>
+        <AttendeeList />
+      </StyledManage>
     </AppLayout>
path: apps/mobile/src/app/manage/page.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**페이지 구조가 체계적으로 잘 구성되었어요**

전체적인 페이지 구조가 아주 체계적으로 잘 구성되었어요! AppLayout 안에 StyledManage를 넣고, 그 안에 다시 Column과 AttendeeList를 배치해서 레이아웃이 깔끔하게 정리되었네요.

하나 개선할 점이 있다면, ActionButton의 onClick 핸들러가 비어있어요. 지금은 아무 동작도 하지 않는 빈 함수(`() => {}`)를 전달하고 있어요. 나중에 실제 기능을 구현할 계획이 있으신 것 같은데, 임시로라도 사용자에게 피드백을 주는 게 좋을 것 같아요:

```diff
- <ActionButton icon="ADD_ICON" background={color.primary} onClick={() => {}}>
+ <ActionButton icon="ADD_ICON" background={color.primary} onClick={() => {
+   // TODO: 참석자 추가 기능 구현 예정
+   alert('참석자 추가 기능은 현재 개발 중입니다.');
+ }}>
```

이렇게 하면 사용자가 버튼을 클릭했을 때 최소한의 피드백을 받을 수 있어요! 😊



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    <AppLayout footer backgroundColor={color.G0}>
      <StyledManage>
        <Column gap={20}>
          <Text fontType="H2" color={color.G900}>
            참석자 관리
          </Text>
          <ActionButton
            icon="ADD_ICON"
            background={color.primary}
            onClick={() => {
              // TODO: 참석자 추가 기능 구현 예정
              alert('참석자 추가 기능은 현재 개발 중입니다.');
            }}
          >
            참석자 추가
          </ActionButton>
        </Column>
        <AttendeeList />
      </StyledManage>
    </AppLayout>
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-03T12:45:46Z
author_association: NONE
diff_hunk: @@ -0,0 +1,65 @@
+import { Side } from '@/types/manage/client';
+import { formatSide } from '@/utils/formatSide';
+import { color } from '@merried/design-system';
+import { IconPencil } from '@merried/icon';
+import { Column, Row, Text } from '@merried/ui';
+import { flex } from '@merried/utils';
+import styled from 'styled-components';
+
+interface ListItemProps {
+  name: string;
+  side: Side;
+  count: number;
+  attend: boolean;
+  money: boolean;
+  meal: boolean;
+}
+
+const ListItem = ({ name, side, count, attend, money, meal }: ListItemProps) => {
+  return (
+    <StyledListItem onClick={() => {}}>
+      <Row alignItems="center" gap={10}>
+        <IconPencil width={16} height={16} />
+        <Column alignItems="flex-start">
+          <Text fontType="P3" color={color.G900}>
+            {name}
+          </Text>
+          <Row alignItems="center" gap={4}>
+            <Text fontType="P3" color={color.G70}>
+              {formatSide[side]}측
+            </Text>
+            <Text fontType="P3" color={color.G70}>
+              •
+            </Text>
+            <Text fontType="P3" color={color.G70}>
+              본인 포함 {count}명
+            </Text>
+          </Row>
+        </Column>
+      </Row>
+      <Row alignItems="center" justifyContent="space-between" width={127}>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {attend === true ? 'O' : 'X'}
+        </Text>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {money === true ? 'O' : 'X'}
+        </Text>
+        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
+          {meal === true ? 'O' : 'X'}
+        </Text>
+      </Row>
+    </StyledListItem>
+  );
+};
path: apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**컴포넌트 구조가 잘 설계되었어요**

`ListItem` 컴포넌트의 구조가 아주 체계적이고 잘 설계되었어요! 연필 아이콘, 이름, 측(신랑/신부), 인원수, 그리고 참석/축의금/식권 상태를 깔끔하게 표시하고 있네요.

몇 가지 개선할 점이 있어요:

1. 현재 onClick 핸들러가 비어있어요(`onClick={() => {}}`). 아이템을 클릭했을 때 어떤 동작을 할 예정인가요? 나중에 기능을 추가할 계획이라면 TODO 주석을 추가하는 것이 좋겠어요.

2. 참석/축의금/식권 상태를 'O'와 'X'로 표시하고 있는데, 시각적으로는 아이콘을 사용하면 더 직관적일 수 있어요. 예를 들어 체크 아이콘(✓)과 엑스 아이콘(✗)을 사용하는 건 어떨까요?

3. 접근성을 위해 상태 표시에 의미적인 레이블을 추가하면 좋을 것 같아요.

```diff
- <Text fontType="P3" color={color.G900} width={25} textAlign="center">
-   {attend === true ? 'O' : 'X'}
- </Text>
+ <Text 
+   fontType="P3" 
+   color={color.G900} 
+   width={25} 
+   textAlign="center" 
+   aria-label={attend ? '참석함' : '참석하지 않음'}
+ >
+   {attend === true ? 'O' : 'X'}
+ </Text>
```

이런 작은 개선들이 사용자 경험을 더 좋게 만들 수 있어요! 🌈



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
const ListItem = ({ name, side, count, attend, money, meal }: ListItemProps) => {
  return (
    <StyledListItem onClick={() => { /* TODO: handle click */ }}>
      <Row alignItems="center" gap={10}>
        <IconPencil width={16} height={16} />
        <Column alignItems="flex-start">
          <Text fontType="P3" color={color.G900}>
            {name}
          </Text>
          <Row alignItems="center" gap={4}>
            <Text fontType="P3" color={color.G70}>
              {formatSide[side]}측
            </Text>
            <Text fontType="P3" color={color.G70}>
              •
            </Text>
            <Text fontType="P3" color={color.G70}>
              본인 포함 {count}명
            </Text>
          </Row>
        </Column>
      </Row>
      <Row alignItems="center" justifyContent="space-between" width={127}>
        <Text
          fontType="P3"
          color={color.G900}
          width={25}
          textAlign="center"
          aria-label={attend ? '참석함' : '참석하지 않음'}
        >
          {attend === true ? 'O' : 'X'}
        </Text>
        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
          {money === true ? 'O' : 'X'}
        </Text>
        <Text fontType="P3" color={color.G900} width={25} textAlign="center">
          {meal === true ? 'O' : 'X'}
        </Text>
      </Row>
    </StyledListItem>
  );
};
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-03T12:45:46Z
author_association: NONE
diff_hunk: @@ -0,0 +1,64 @@
+import { color, font } from '@merried/design-system';
+import { IconSearch } from '@merried/icon';
+import { flex } from '@merried/utils';
+import { CSSProperties, InputHTMLAttributes, useRef } from 'react';
+import styled from 'styled-components';
+
+export interface SearchInputProps extends InputHTMLAttributes<HTMLInputElement> {
+  width?: CSSProperties['width'];
+}
+
+const SearchInput = ({
+  width,
+  onChange,
+  value,
+  name,
+  placeholder,
+  type = 'text',
+}: SearchInputProps) => {
+  const inputRef = useRef<HTMLInputElement>(null);
+
+  const handleClick = () => {
+    inputRef.current?.focus();
+  };
+
+  return (
+    <StyledSearchInput onClick={handleClick} style={{ width }}>
+      <Input
+        placeholder={placeholder}
+        onChange={onChange}
+        value={value}
+        name={name}
+        type={type}
+      />
+      <IconSearch width={16} height={16} />
+    </StyledSearchInput>
+  );
+};
path: apps/mobile/src/components/manage/SearchInput/SearchInput.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**컴포넌트 구현이 알맞게 되었지만, ref 설정이 빠졌어요! 🔍**

SearchInput 컴포넌트의 구현이 전반적으로 잘 되어 있어요. 특히 클릭 시 입력란에 포커스되도록 하는 기능을 추가한 점이 사용자 경험을 높여줄 거예요.

하지만! 중요한 부분이 빠졌어요. useRef로 참조를 만들었지만, 실제 Input 요소에 ref를 연결하지 않았어요. 그래서 클릭 시 포커스 기능이 작동하지 않아요.


```diff
<StyledSearchInput onClick={handleClick} style={{ width }}>
  <Input
+    ref={inputRef}
    placeholder={placeholder}
    onChange={onChange}
    value={value}
    name={name}
    type={type}
  />
  <IconSearch width={16} height={16} />
</StyledSearchInput>
```

이렇게 Input 컴포넌트에 ref를 연결해주면, handleClick 함수가 제대로 작동해서 클릭했을 때 입력란에 포커스가 잘 될 거예요! 😄

또한, 접근성을 높이기 위해 아이콘에 aria-hidden 속성을 추가하는 것이 좋을 것 같아요:

```diff
-<IconSearch width={16} height={16} />
+<IconSearch width={16} height={16} aria-hidden="true" />
```

이렇게 하면 스크린 리더가 불필요하게 아이콘을 읽지 않게 되어 접근성이 향상돼요! 💕

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-03T12:45:46Z
author_association: NONE
diff_hunk: @@ -0,0 +1,6 @@
+import { Side } from '@/types/manage/client';
+
+export const formatSide: Record<Side, string> = {
+  GROOM: '신랑',
+  BRIDE: '신부',
+};
path: apps/mobile/src/utils/formatSide.ts
user: login: MinjuN07
body: 해당 부분은 유틸 함수보다는 상수(contants)에 가깝지 않나 조심스럽게 말씀드립니다.
created_at: 2025-05-03T14:25:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,6 @@
+import { Side } from '@/types/manage/client';
+
+export const formatSide: Record<Side, string> = {
+  GROOM: '신랑',
+  BRIDE: '신부',
+};
path: apps/mobile/src/utils/formatSide.ts
user: login: junghongseop
body: 맞는거 갔습니다. 수정하겠습니다.
created_at: 2025-05-03T14:27:47Z
author_association: MEMBER

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-03T12:42:37Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: failure by coderabbit.ai -->

> [!CAUTION]
> ## Review failed
> 
> The pull request is closed.

<!-- end of auto-generated comment: failure by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

이번 변경에서는 참석자 관리 페이지를 새롭게 구성했어요. 이제 참석자 목록을 검색하고, 각 참석자 정보를 보기 쉽게 정리된 UI로 볼 수 있어요. 새로운 컴포넌트들이 추가되어, 참석자 리스트, 리스트 헤더, 리스트 아이템, 검색 입력창 등이 만들어졌고, 이를 위한 타입과 상수, 아이콘도 추가되었어요. 버튼 스타일도 개선되어 배경색을 지정할 수 있게 되었고, 전체적으로 구조화된 화면과 상호작용이 가능해졌답니다.

## Changes

| 파일 또는 그룹 | 변경 요약 |
|---|---|
| `apps/mobile/src/app/manage/page.tsx` | 참석자 관리 페이지 UI를 구조화하고, 참석자 리스트 및 추가 버튼 등 새로운 레이아웃 적용 |
| `apps/mobile/src/components/manage/AttendeeList/AttendeeList.tsx`<br>`.../ListHeader/ListHeader.tsx`<br>`.../ListItem/ListItem.tsx` | 참석자 리스트, 리스트 헤더, 리스트 아이템 컴포넌트 새로 추가 및 내보내기 |
| `apps/mobile/src/components/manage/SearchInput/SearchInput.tsx` | 검색 입력창 컴포넌트 추가 및 내보내기, 입력 포커스 기능 포함 |
| `apps/mobile/src/types/manage/client.ts` | 참석자 구분을 위한 `Side` 타입(GROOM/BRIDE) 추가 |
| `apps/mobile/src/constants/common/constant.ts` | `Side` 타입에 맞는 한글 매핑 상수 `SIDE` 추가 |
| `packages/icon/index.ts`<br>`src/IconSearch.tsx`<br>`src/IconPencil.tsx` | 검색 및 연필 아이콘 컴포넌트 추가 및 내보내기 |
| `packages/ui/src/Button/ActionButton.tsx` | `ActionButton`에 배경색 지정 기능 추가, 텍스트 스타일 개선 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant 사용자
    participant ManagePage
    participant SearchInput
    participant AttendeeList
    participant ListHeader
    participant ListItem

    사용자->>ManagePage: 페이지 접근
    ManagePage->>SearchInput: 검색창 렌더링
    ManagePage->>AttendeeList: 참석자 리스트 렌더링
    AttendeeList->>ListHeader: 리스트 헤더 표시
    AttendeeList->>ListItem: 각 참석자 정보 표시
    사용자->>SearchInput: 검색어 입력
    SearchInput->>AttendeeList: 검색어 전달
    AttendeeList->>ListItem: 필터링된 참석자 표시
```

## Poem

> 🎉  
> 새로운 참석자 관리, 반짝이는 UI  
> 신랑 신부 구분도, 한눈에 쏙쏙!  
> 검색창에 이름 쓰면, 리스트가 쏙쏙  
> 연필 아이콘 반짝이며, 수정이 준비돼요  
> 모두 함께 모여서, 관리가 쉬워졌네!  
> 👰🤵✨  
>

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
> 
> From ESLint v9.0.0, the default configuration file is now eslint.config.js.
> If you are using a .eslintrc.* file, please follow the migration guide
> to update your configuration file to the new format:
> 
> https://eslint.org/docs/latest/use/configure/migration-guide
> 
> If you still have problems after following the migration guide, please stop by
> https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>apps/mobile/src/constants/common/constant.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
> 
> From ESLint v9.0.0, the default configuration file is now eslint.config.js.
> If you are using a .eslintrc.* file, please follow the migration guide
> to update your configuration file to the new format:
> 
> https://eslint.org/docs/latest/use/configure/migration-guide
> 
> If you still have problems after following the migration guide, please stop by
> https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between aac6b6e4ab113a5c7cf616aa7355b18a59fca906 and e2084f6e0538d6aeec23493fe6b954c44a5e689a.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `apps/mobile/src/components/manage/AttendeeList/ListItem/ListItem.tsx` (1 hunks)
* `apps/mobile/src/constants/common/constant.ts` (1 hunks)

</details>

</details>
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=WillYouMerryMe/getting-married&utm_content=32):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: akns27
created_at: 2025-05-03T13:14:04Z
body: 구현 잘하셨네요!
author_association: CONTRIBUTOR