Skip to content

Commit

Permalink
fix: 타입 error 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
imfineimgood committed Jan 3, 2025
1 parent e06e8cb commit d8845c6
Show file tree
Hide file tree
Showing 12 changed files with 474 additions and 380 deletions.
37 changes: 37 additions & 0 deletions src/@lib/components/AppContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useTheme } from "../contexts/ThemeContext";
import { memo } from "../hocs";
import { Item } from "../types";
import { ComplexForm } from "./ComplexForm";
import { Header } from "./Header";
import { ItemList } from "./ItemList";
import { NotificationSystem } from "./NotificationSystem";

interface AppContentProps {
items: Item[];
onAddItems: () => void;
}

export const AppContent: React.FC<AppContentProps> = memo(
({ items, onAddItems }) => {
const { theme } = useTheme();

return (
<div
className={`min-h-screen ${theme === "light" ? "bg-gray-100" : "bg-gray-900 text-white"}`}
>
<Header />
<div className="container mx-auto px-4 py-8">
<div className="flex flex-col md:flex-row">
<div className="w-full md:w-1/2 md:pr-4">
<ItemList items={items} onAddItemsClick={onAddItems} />
</div>
<div className="w-full md:w-1/2 md:pl-4">
<ComplexForm />
</div>
</div>
</div>
<NotificationSystem />
</div>
);
},
);
96 changes: 96 additions & 0 deletions src/@lib/components/ComplexForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useState } from "react";
import { renderLog } from "../../utils";
import { useNotification } from "../contexts/NotificationContext";
import { memo } from "../hocs";
import { useCallback } from "../hooks";
import { PREFERENCES } from "../constants";

export const ComplexForm: React.FC = memo(() => {
renderLog("ComplexForm rendered");
const { addNotification } = useNotification();
const [formData, setFormData] = useState({
name: "",
email: "",
age: 0,
preferences: [] as string[],
});

const handleSubmit = useCallback(
(e: React.FormEvent) => {
e.preventDefault();
addNotification("폼이 성공적으로 제출되었습니다", "success");
},
[addNotification],
);

const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: name === "age" ? parseInt(value) || 0 : value,
}));
},
[],
);

const handlePreferenceChange = useCallback((preference: string) => {
setFormData((prev) => ({
...prev,
preferences: prev.preferences.includes(preference)
? prev.preferences.filter((p) => p !== preference)
: [...prev.preferences, preference],
}));
}, []);

return (
<div className="mt-8">
<h2 className="text-2xl font-bold mb-4">복잡한 폼</h2>
<form onSubmit={handleSubmit} className="space-y-4">
<input
type="text"
name="name"
value={formData.name}
onChange={handleInputChange}
placeholder="이름"
className="w-full p-2 border border-gray-300 rounded text-black"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleInputChange}
placeholder="이메일"
className="w-full p-2 border border-gray-300 rounded text-black"
/>
<input
type="number"
name="age"
value={formData.age}
onChange={handleInputChange}
placeholder="나이"
className="w-full p-2 border border-gray-300 rounded text-black"
/>
<div className="space-x-4">
{PREFERENCES.map((pref) => (
<label key={pref} className="inline-flex items-center">
<input
type="checkbox"
checked={formData.preferences.includes(pref)}
onChange={() => handlePreferenceChange(pref)}
className="form-checkbox h-5 w-5 text-blue-600"
/>
<span className="ml-2">{pref}</span>
</label>
))}
</div>
<button
type="submit"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
제출
</button>
</form>
</div>
);
});
50 changes: 50 additions & 0 deletions src/@lib/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { renderLog } from "../../utils";
import { useTheme } from "../contexts/ThemeContext";
import { useUser } from "../contexts/UserContext";
import { memo } from "../hocs";
import { useCallback } from "../hooks";

export const Header: React.FC = memo(() => {
renderLog("Header rendered");
const { theme, toggleTheme } = useTheme();
const { user, login, logout } = useUser();

const handleLogin = useCallback(() => {
// 실제 애플리케이션에서는 사용자 입력을 받아야 합니다.
login("[email protected]", "password");
}, []);

return (
<header className="bg-gray-800 text-white p-4">
<div className="container mx-auto flex justify-between items-center">
<h1 className="text-2xl font-bold">샘플 애플리케이션</h1>
<div className="flex items-center">
<button
onClick={toggleTheme}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mr-2"
>
{theme === "light" ? "다크 모드" : "라이트 모드"}
</button>
{user ? (
<div className="flex items-center">
<span className="mr-2">{user.name}님 환영합니다!</span>
<button
onClick={logout}
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
>
로그아웃
</button>
</div>
) : (
<button
onClick={handleLogin}
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
>
로그인
</button>
)}
</div>
</div>
</header>
);
});
69 changes: 69 additions & 0 deletions src/@lib/components/ItemList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState } from "react";
import { renderLog } from "../../utils";
import { memo } from "../hocs";
import { Item } from "../types";
import { useTheme } from "../contexts/ThemeContext";
import { useMemo } from "../hooks";

export const ItemList = memo<{
items: Item[];
onAddItemsClick: () => void;
}>(({ items, onAddItemsClick }) => {
renderLog("ItemList rendered");
const [filter, setFilter] = useState("");

const { theme } = useTheme();

const filteredItems = useMemo(
() =>
items.filter(
(item) =>
item.name.toLowerCase().includes(filter.toLowerCase()) ||
item.category.toLowerCase().includes(filter.toLowerCase()),
),
[items, filter],
);

const totalPrice = filteredItems.reduce((sum, item) => sum + item.price, 0);

const averagePrice = Math.round(totalPrice / filteredItems.length) || 0;

return (
<div className="mt-8">
<div className="flex justify-between items-center mb-4">
<h2 className="text-2xl font-bold">상품 목록</h2>
<div>
<button
type="button"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded text-xs"
onClick={onAddItemsClick}
>
대량추가
</button>
</div>
</div>
<input
type="text"
placeholder="상품 검색..."
value={filter}
onChange={(e) => setFilter(e.target.value)}
className="w-full p-2 mb-4 border border-gray-300 rounded text-black"
/>
<ul className="mb-4 mx-4 flex gap-3 text-sm justify-end">
<li>검색결과: {filteredItems.length.toLocaleString()}</li>
<li>전체가격: {totalPrice.toLocaleString()}</li>
<li>평균가격: {averagePrice.toLocaleString()}</li>
</ul>
<ul className="space-y-2">
{filteredItems.map((item, index) => (
<li
key={index}
className={`p-2 rounded shadow ${theme === "light" ? "bg-white text-black" : "bg-gray-700 text-white"}`}
>
{item.name} - {item.category} - {item.price.toLocaleString()}
</li>
))}
</ul>
</div>
);
});
36 changes: 36 additions & 0 deletions src/@lib/components/NotificationSystem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { renderLog } from "../../utils";
import { useNotification } from "../contexts/NotificationContext";
import { memo } from "../hocs";

// NotificationSystem 컴포넌트
export const NotificationSystem: React.FC = memo(() => {
renderLog("NotificationSystem rendered");
const { notifications, removeNotification } = useNotification();

return (
<div className="fixed bottom-4 right-4 space-y-2">
{notifications.map((notification) => (
<div
key={notification.id}
className={`p-4 rounded shadow-lg ${
notification.type === "success"
? "bg-green-500"
: notification.type === "error"
? "bg-red-500"
: notification.type === "warning"
? "bg-yellow-500"
: "bg-blue-500"
} text-white`}
>
{notification.message}
<button
onClick={() => removeNotification(notification.id)}
className="ml-4 text-white hover:text-gray-200"
>
닫기
</button>
</div>
))}
</div>
);
});
2 changes: 2 additions & 0 deletions src/@lib/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const PREFERENCES = ["독서", "운동", "음악", "여행"] as const;
export const INITIAL_ITEMS_COUNT = 1000;
71 changes: 71 additions & 0 deletions src/@lib/contexts/NotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// contexts/NotificationContext.tsx
import { createContext, useContext, useState } from "react";
import { Notification } from "../types";
import { useMemo } from "../hooks";

const NotificationsContext = createContext<Notification[] | undefined>(
undefined,
);

interface NotificationActionsType {
addNotification: (message: string, type: Notification["type"]) => void;
removeNotification: (id: number) => void;
}

const NotificationActionsContext = createContext<
NotificationActionsType | undefined
>(undefined);

export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [notifications, setNotifications] = useState<Notification[]>([]);

const actions = useMemo(
() => ({
addNotification: (message: string, type: Notification["type"]) => {
const newNotification: Notification = {
id: Date.now(),
message,
type,
};
setNotifications((prev) => [...prev, newNotification]);
},
removeNotification: (id: number) => {
setNotifications((prev) =>
prev.filter((notification) => notification.id !== id),
);
},
}),
[],
);

return (
<NotificationActionsContext.Provider value={actions}>
<NotificationsContext.Provider value={notifications}>
{children}
</NotificationsContext.Provider>
</NotificationActionsContext.Provider>
);
};

export const useNotifications = () => {
const context = useContext(NotificationsContext);
if (!context)
throw new Error("NotificationProvider 내에서 사용되어야 합니다.");
return context;
};

export const useNotificationActions = () => {
const context = useContext(NotificationActionsContext);
if (!context)
throw new Error("NotificationProvider 내에서 사용되어야 합니다.");
return context;
};

export const useNotification = () => {
return {
notifications: useNotifications(),
...useNotificationActions(),
};
};
Loading

0 comments on commit d8845c6

Please sign in to comment.