Skip to content
/ mall Public

๋“œ๋ฆผ์ฝ”๋”ฉ-๐Ÿ‘Ÿrunz. ์šด๋™๋ณต ์‡ผํ•‘๋ชฐ ํ™ˆํŽ˜์ด์ง€ ์ œ์ž‘

Notifications You must be signed in to change notification settings

moonjieun/mall

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

49 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ”ผ ํด๋ฆญ์‹œ ์‚ฌ์ดํŠธ ์ด๋™

์šด๋™๋ณต ์‡ผํ•‘๋ชฐ ํ™ˆํŽ˜์ด์ง€ (๊ฐœ์ธํ”„๋กœ์ ํŠธ)



๐Ÿ“ํ”„๋กœ์ ํŠธ ์ •๋ณด

๐Ÿ’ก ๊ฐœ๋ฐœ๊ธฐ๊ฐ„

  • 2023.03.29 ~ 2023.04.27

๐Ÿ”จ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉ๋œ ๊ธฐ์ˆ 



๐Ÿ“Ž ํ™ˆํŽ˜์ด์ง€ ๊ตฌ์„ฑ

  • Home
  • Product Detail Page
  • My Cart
  • New Product ( admin๊ถŒํ•œ์ด ์žˆ๋Š” ์‚ฌ์šฉ์ž๋งŒ ๋ณด์ด๋Š” ํŽ˜์ด์ง€ ) ๊ด€๋ฆฌ์ž๋งŒ ์ƒˆ์ƒํ’ˆ ๋“ฑ๋ก
  • Login, Logout ( ๊ตฌ๊ธ€๊ณ„์ • ๋กœ๊ทธ์ธ )

๐Ÿ”Ž ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋ณด๊ธฐ

1. ๋กœ๊ทธ์ธ ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ

โ— ์˜ค๋ฅ˜ ์‚ฌํ•ญ
Navbar์—์„œ useState๋“ฑ๋ก | useEffect์„ ํ†ตํ•ด user์ •๋ณด๋ฅผ Component์— ๋“ฑ๋กํ•˜์˜€๋”๋‹ˆ, ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋”ฉ์‹œ ์ •๋ณด ์ดˆ๊ธฐํ™” ์œ ์ €์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ์ง€ ๋ชปํ•˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ์ˆ˜์ • ๋‚ด์šฉ
    Context Api ์ด์šฉํ•ด user๋ฅผ ๋“ฑ๋ก Navbar์—์„œ useAuthContext๋กœ <AuthContext.Provider/>๋กœ ๊ฐ์‹ผ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ํ•˜์˜€๊ณ , ๋ฆฌ๋กœ๋”ฉ์‹œ์—๋„ ์œ ์ €์ •๋ณด ๋ณด๊ด€
๐Ÿ’ฌ์ฝ”๋“œ๋ณด๊ธฐ
/**๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ๊ฒฐ๊ณผ๊ฐ’๋ฐ›๋Š”ํ•จ์ˆ˜ */
export function onUserStateChange(callback) {
  onAuthStateChanged(auth, async (user) => {
    const updatedUser = user ? await adminUser(user) : null;
    callback(updatedUser);
  });
}

๏ผŠ login(), logout()์€ ๋ช…๋ นํ˜• ํ•จ์ˆ˜๋กœ๋งŒ ์ด์šฉ


2. ๋กœ๊ทธ์ธ์‹œ ์–ด๋“œ๋ฏผ๊ถŒํ•œ ํ™•์ธ

  • ์–ด๋“œ๋ฏผ ์‚ฌ์šฉ์ž ๊ฒฝ๋กœ๋ณดํ˜ธ index.js <ProtectedRoute/>์‚ฌ์šฉํ•˜์—ฌ ProtectedRoute.jsx Component์—์„œ ์กฐ๊ฑด์„ ์ฒดํฌํ•œ๋’ค route๋ฅผ์ด์šฉํ•ด ์ƒˆ์ƒํ’ˆ๋“ฑ๋กํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒํ•˜์˜€์Šต๋‹ˆ๋‹ค.( ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์žํ™•์ธ, ์–ด๋“œ๋ฏผ๊ถŒํ•œ์ฒดํฌ )
๐Ÿ’ฌ์ฝ”๋“œ๋ณด๊ธฐ
import React from 'react';
import { useAuthContext } from '../context/AuthContext';
import { Navigate } from 'react-router-dom';

export default function ProtectedRoute({children, requireAdmin}){
    const { user } = useAuthContext();
   console.log(user,'๋‚˜ ๋ผ์šฐํ„ฐํŽ˜์ด์ง€์ž„ ์œ ์ €์ •๋ณด ๋œจ๋Š”์ง€ ์ข€')
   if(user===undefined){
    return <>๋กœ๋”ฉ์ค‘</>;
 } else if (user === null || (requireAdmin && user.isAdmin===false)) {
    return <Navigate to={"/"} replace={true} />;
 } else {
    return children;
 }
}

//๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ๋Š”์ง€ํ™•์ธ
//์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋“œ๋ฏผ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
//requireAdmin์ด true์ธ ๊ฒฝ์šฐ์—๋Š” ๋กœ๊ทธ์ธ๋„ ๋˜์–ด์žˆ์–ด์•ผํ•˜๊ณ , ์–ด๋“œ๋ฏผ ๊ถŒํ•œ๋„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผํ•จ\
//์กฐ๊ฑด์ด ๋ถˆ์ถฉ์กฑํ• ๊ฒฝ์šฐ / ์ƒ์œ„ ๊ฒฝ๋กœ๋กœ ์ด๋™
//์กฐ๊ฑด์ด ์ถฉ์กฑ๋œ๊ฒฝ์šฐ ์ „๋‹ฌ๋œ chidren์„ ๋ณด์—ฌ์คŒ

์‹คํ–‰ํ™”๋ฉด

๐Ÿ’ฌ์ƒํ’ˆ๊ด€๋ฆฌ ๊ถŒํ•œ ์ฝ”๋“œ๋ณด๊ธฐ
/**์ƒํ’ˆ๊ด€๋ฆฌ ๊ถŒํ•œ  ์ฒดํฌ  */
//firebase/admins์— ๋ฏธ๋ฆฌ ๊ถŒํ•œ์„์ค„ uid๋ฅผ ๋“ฑ๋ก
async function adminUser(user) {
  return get(ref(database, "admins")).then((snapshot) => {
    if (snapshot.exists()) {
      const admins = snapshot.val();
      console.log(admins);
      const isAdmin = admins.includes(user.uid);
      return { ...user, isAdmin };
    }
    return user;
  });
}

3. custom hook, useMutation์˜ ์‚ฌ์šฉ


๐Ÿ“ (์ˆ˜์ •์ „) ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
const {
  isLoading,
  error,
  data: products,
} = useQuey(["products"], getProducts, { staleTime: 1000 * 60 });

  • (์ˆ˜์ •ํ›„) custom hook ์‚ฌ์šฉ ํ›„ ์ฝ”๋“œ๋ฆฌํŒฉํ† ๋ง โœจ
const {
  productsQuery: { isLoading, error, data: products },
} = useProducts();

reactQuery ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด, UI/business ๋กœ์ง ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด custom hook์„ ์ด์šฉํ•ด ์š”์ฒญ/ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ๊ณณ์—์„œ ๊ด€๋ฆฌํ•˜๊ฒŒ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.


4. ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฑƒ์ง€ ํ‘œ์‹œ์ง€์—ฐ ์ˆ˜์ •

๐Ÿ“‘ ๊ฐœ์„ ์‚ฌํ•ญ

์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ๊ฐœ์ˆ˜๋ฅผ ๋ฐ”๋กœ ํ™•์ธํ•˜์ง€ ๋ชปํ•˜์˜€์œผ๋‚˜, firebaseํŒŒ์ผํ•จ์ˆ˜๋ฅผ component์—์„œ ์‚ฌ์šฉํ•˜์ง€์•Š๊ณ  custom hook์—์„œ ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„์™€ mutate(์ •๋ณด)๋ฅผ ์ด์šฉํ•ด ์ „๋‹ฌ -> ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌํ˜ธ์ถœํ•ด ์ตœ์‹ ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธ

๐Ÿ’ก ๊ฐœ์„  ํ›„ ์‹คํ–‰ํ™”๋ฉด


cart custom hook ์ฝ”๋“œ

๐Ÿ’ฌ์ž์„ธํžˆ๋ณด๊ธฐ
export default function useCart() {
  const queryClient = useQueryClient();

  const { uid } = useAuthContext();
  /**์‚ฌ์šฉ์ž๋ณ„๋กœ ์บ์‹œ ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ๋Š”๊ฒฝ์šฐ์—๋งŒ apiquery์‚ฌ์šฉ */
  const cartQuery = useQuery(["carts", uid || ""], () => getCart(uid), {
    enabled: !!uid,
  });

  const addOrUpdateItem = useMutation(
    (product) => addOrUpdateToCart(uid, product),
    {
      onSuccess: () => {
        queryClient.invalidateQueries(["carts", uid]);
      },
    }
  );

  const removeItem = useMutation((id) => removeFromCart(uid, id), {
    onSuccess: () => {
      queryClient.invalidateQueries(["carts", uid]);
    },
  });

  return { cartQuery, addOrUpdateItem, removeItem };
}

5. cloudinary์—์„œ REST API๋ฅผ ์ด์šฉํ•ด ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ

export async function uploadImage(file) {
  const data = new FormData();

  data.append("file", file);
  //secret key => .env
  data.append("upload_preset", process.env.REACT_APP_CLOUDINARY_PRESET);
  return fetch(process.env.REACT_APP_CLOUDINARY_URL, {
    method: "POST",
    body: data,
  })
    .then((res) => res.json())
    .then((data) => data.url);
}
  • ์—ฌ๊ธฐ์„œ ์ด๋ฏธ์ง€URL์„ ๋ฐ›์•„์™€ firbase์— ํŒŒ์ผํ˜•ํƒœ X => urlํ˜•ํƒœ๋กœ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

About

๋“œ๋ฆผ์ฝ”๋”ฉ-๐Ÿ‘Ÿrunz. ์šด๋™๋ณต ์‡ผํ•‘๋ชฐ ํ™ˆํŽ˜์ด์ง€ ์ œ์ž‘

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published