https://realfavicongenerator.net/
"use Client";
import { useAuth } from "@/context/auth.context";
import React, { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { Separator } from "./Separator";
import WeatherData from "./WeatherData";
import {
Sheet,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "./Sheet";
import { Weather } from "@/types/weather";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
import { Card, CardContent, CardDescription, CardTitle } from "./Card";
import LogoutLoader from "./LogoutLoader";
const SideBar = ({
children,
isOpen,
handleOpen,
}: {
children: React.ReactNode;
isOpen: boolean;
handleOpen: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const { me, logOut } = useAuth();
const handleClickLogout = () => {
//로더를 띄우거나 (1)
//화면을 천천히 사라지게
//transition
LogoutLoader;
logOut();
};
const handleClick = () => {
handleOpen(false);
};
// if (!me) return BasicLoader;
//이 부분 때문에, 로그인 안 됐을 때 SideBar를 누를 수 있는 버튼이 없어졌었다
//return null 대신 스켈레톤이나 loading을 알려줄 수 잇는 거 추가하기
//SideBar에서 로그아웃 눌렀을 때 로더 뜨면서 로그인 페이지로 이동됨
//로그아웃 상태면 메인페이지에서 좌측상단 얼굴 없어짐
const [weather, setWeather] = useState<Weather["weather"] | null>(null);
const [tempMin, setTempMin] = useState<number | null>(null);
const [tempMax, setTempMax] = useState<number | null>(null);
const [humidity, setHumidity] = useState<number | null>(null);
const [temp, setTemp] = useState<number | null>(null);
const handleWeatherData = (
weatherData: Weather["weather"],
temperature: number,
minimumTemp: number,
maximumTemp: number,
humidityLevel: number
) => {
setWeather(weatherData);
setTempMin(minimumTemp);
setTempMax(maximumTemp);
setHumidity(humidityLevel);
setTemp(temperature);
};
return (
<div className="w-[10%]">
{/* as Child 삭제해도 동작하는 이유? */}
<Sheet open={isOpen}>
<SheetTrigger asChild>{children}</SheetTrigger>
{/* hover시 cursor 바뀌게 수정해야 함! */}
<SheetContent
className="font-Pretendard-Regular"
handleClick={handleClick}
>
<SheetHeader>
{me && me.userTableInfo ? (
<>
<Image
src={me.userTableInfo.avatar as string | StaticImport}
alt="profile_btn"
className="rounded-full"
width={67}
height={34}
/>
<SheetTitle>{me.userTableInfo.nickname}</SheetTitle>
<div className="flex flex-col items-start">
<SheetDescription>
{me.userTableInfo.introduction
? me.userTableInfo.introduction
: "자기소개를 추가해주세요"}
</SheetDescription>
<SheetDescription>@{me.userTableInfo.email}</SheetDescription>
</div>
</>
) : (
<div>로딩중</div>
)}
</SheetHeader>
<Link href="/profile">
<div className="flex flex-row mt-3 mb-3">
<Image
className="mr-3"
src="/profile_icon.svg"
width={17}
height={14}
alt="profile_icon"
/>
<SheetTitle className="font-semibold text-md text-slate-700">
내 프로필
</SheetTitle>
</div>
</Link>
<Link href="/write">
<div className="flex flex-row mb-10">
<Image
className="mr-3"
src="/write_icon.svg"
alt="write_icon"
width={17}
height={17}
/>
<SheetTitle className="font-semibold text-md text-slate-700">
글 작성하기
</SheetTitle>
</div>
</Link>
<Separator />
{/* <h3>날씨</h3> */}
<WeatherData onWeatherData={handleWeatherData} />
{weather && tempMin && tempMax && humidity ? (
<Card className="font-Cafe24SsurroundAir max-w-80 max-h-40 mt-10 mb-10 bg-turtleGreen/60">
<div className="flex flex-col items-center">
<CardTitle>
{weather && weather[0] && (
<Image
src={weather[0].iconUrl}
alt={weather[0].description}
width={53}
height={53}
/>
)}
</CardTitle>
<CardTitle className="text-xl">
{weather[0].description}
</CardTitle>
<CardDescription className="mb-3">
{`${temp?.toFixed(1)}°C`}
</CardDescription>
</div>
<CardContent className="text-[12px] ml-1 font-semibold flex flex-row items-center">
<p className="ml-3 mr-3">{`🔽최저 ${tempMin.toFixed(1)}°C`}</p>
<p className="ml-5 mr-3">{`🔼최고 ${tempMax.toFixed(1)}°C`}</p>
<p className="ml-3 mr-3">{`💧습도 ${humidity.toFixed(1)}%`}</p>
</CardContent>
</Card>
) : (
<Card className="text-center font-semibold grid place-items-center font-Cafe24SsurroundAir mt-10 mb-10 bg-turtleGreen/60 w-[270px] h-[162px]">
<p>오늘의 날씨는?</p>
</Card>
)}
<SheetFooter className="flex flex-row justify-center">
{/* <SheetClose asChild>
<button onClick={handleClick}>닫기</button>
</SheetClose> */}
<button
onClick={handleClickLogout}
className="w-[67px] h-[34px] bg-[#B7E6CB] text-white font-semi-bold text-sm py-0 px-1 rounded-full hover:bg-[#073A33] transition duration-300 ease-in-out flex items-center justify-center"
>
Logout
</button>
</SheetFooter>
</SheetContent>
</Sheet>
</div>
);
};
export default SideBar;
"use client";
import { Weather } from "@/types/weather";
import React, { useEffect } from "react";
// WeatherData 컴포넌트 속 interface는 TypeScript에서 컴포넌트의 props를 정의하는 데 사용됩니다.
// 이는 코드의 가독성을 높이고 타입 검사를 통해 컴파일 타임에 오류를 방지하는 데 도움이 됩니다.
// 아래는 WeatherData 컴포넌트에서 WeatherDataProps 인터페이스를 왜 사용하는지 설명합니다.
// 이유 1: 타입 안전성 제공
// WeatherData 컴포넌트가 onWeatherData라는 콜백 함수를 prop으로 받습니다.
// 이 콜백 함수의 인자는 날씨 데이터와 관련된 여러 값들입니다. 인터페이스를 사용하면 이 prop의 타입을 명시적으로 정의할 수 있습니다. 이는 타입 안전성을 제공하고, 잘못된 타입의 데이터가 전달되는 것을 방지합니다.
// 이유 2: 코드 가독성 향상
// 인터페이스를 사용하면 컴포넌트가 어떤 props를 기대하는지 명확히 알 수 있습니다.
// 이는 코드의 가독성을 높이고, 다른 개발자가 코드를 읽을 때 prop의 구조를 쉽게 이해할 수 있게 합니다.
// 이유 3: 자동 완성 지원
// TypeScript 인터페이스를 사용하면 IDE에서 prop에 대한 자동 완성을 지원합니다.
// 이는 개발 생산성을 높이고, 코드 작성 중에 실수를 줄이는 데 도움이 됩니다.
interface WeatherDataProps {
onWeatherData: (
weather: Weather["weather"],
temp: number,
tempMin: number,
tempMax: number,
humidity: number
) => void;
}
const WeatherData: React.FC<WeatherDataProps> = ({ onWeatherData }) => {
useEffect(() => {
const fetchWeatherData = async () => {
const response = await fetch("/api/weather");
const data: Weather = await response.json();
onWeatherData(
data.weather,
data.main.temp,
data.main.temp_min,
data.main.temp_max,
data.main.humidity
);
};
fetchWeatherData();
}, []);
return null;
};
export default WeatherData;