24.07.12

강연주·2024년 7월 14일

📚 TIL

목록 보기
26/186

[png 이미지를 favicon.ico로 변경하기]

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;
profile
아무튼, 개발자

0개의 댓글