Skip to content

Commit

Permalink
Merge pull request #38 from junhyeon0218/feat/ftiResult
Browse files Browse the repository at this point in the history
♻️ Refactor: fti결과페이지 리팩토링
  • Loading branch information
junhyeon0218 authored Sep 7, 2024
2 parents 5dab352 + a5033e8 commit ea65561
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 112 deletions.
2 changes: 1 addition & 1 deletion src/api/apis/foods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const postAllFoods = async () => {
is_party: false,
is_diet: false,
},
recommends_cnt: 5,
recommends_cnt: 100,
});
return response.data;
} catch (error) {
Expand Down
9 changes: 6 additions & 3 deletions src/api/apis/fti.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { baseInstance } from '../util/instance';
import { baseInstance, authInstance } from '../util/instance';
import { getCookie } from '../../utils/cookie';

export const getFtiQuestions = async () => {
try {
Expand All @@ -12,14 +13,16 @@ export const getFtiQuestions = async () => {

export const sendFtiResult = async (result: string[]) => {
try {
const response = await baseInstance.post('/api/ftitests/result/', { fti_style: result }); // 'results' 키로 전송
const refreshToken = getCookie('refresh'); // 쿠키에서 리프레시 토큰 가져오기
const instance = refreshToken ? authInstance : baseInstance; // 리프레시 토큰이 있으면 authInstance 사용, 없으면 baseInstance 사용

const response = await instance.post('/api/ftitests/result/', { fti_style: result });
return response.data;
} catch (error) {
console.error('Failed to send FTI result:', error);
throw error;
}
};

export const getFtiType = async (uuid: string) => {
try {
const response = await baseInstance.get(`/api/ftitests/result/${uuid}`);
Expand Down
40 changes: 21 additions & 19 deletions src/pages/foods/Foods.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useCallback } from 'react';
import Tag from '../../components/common/Tag';
import FoodCard from '../../components/foods/FoodCard';
import { useFoodStore } from '../../store/foodStore';
import { FoodsList } from '../../types/types';
import { getItem } from '../../utils/storage';
import { postAllFoods } from '../../api/apis/foods';
Expand All @@ -11,7 +10,8 @@ const filter: string[] = ['기본', '점심', '저녁', '간식', '데이트', '
const Foods = () => {
const [selectedTag, setSelectedTag] = useState<string>('기본');
const [filteredFoods, setFilteredFoods] = useState<FoodsList[]>([]);
const { foodsList, setFoodsList } = useFoodStore();
const [sessionFoods, setSessionFoods] = useState<FoodsList[]>([]);
const [apiFoods, setApiFoods] = useState<FoodsList[]>([]);

const handleTagClick = (tag: string) => {
setSelectedTag(tag);
Expand All @@ -28,33 +28,35 @@ const Foods = () => {
return tags;
};

const filterFoods = (tag: string): FoodsList[] => {
if (tag === '기본') {
return foodsList;
}
return foodsList.filter((food) => mapTags(food).includes(tag));
};
const filterFoods = useCallback(
(tag: string): FoodsList[] => {
const combinedFoods = [...sessionFoods, ...apiFoods];
if (tag === '기본') {
return combinedFoods;
}
return combinedFoods.filter((food) => mapTags(food).includes(tag));
},
[sessionFoods, apiFoods],
);

const getAllFoods = async () => {
const response = await postAllFoods();
console.log('All foods fetched:', response.data);
console.log('All foods fetched:', response.recommendations);
setApiFoods(response.recommendations);
};

useEffect(() => {
const recommendedFoods = getItem('foodsList-storage');
if (recommendedFoods) {
const parsedFoods = JSON.parse(recommendedFoods).state.foodsList;
setFoodsList(parsedFoods);
setSessionFoods(parsedFoods);
}
}, [setFoodsList]);
getAllFoods(); // API 호출
}, []);

useEffect(() => {
setFilteredFoods(filterFoods(selectedTag));
}, [selectedTag, foodsList]);

useEffect(() => {
getAllFoods();
}, []);
}, [selectedTag, sessionFoods, apiFoods, filterFoods]);

return (
<div>
Expand All @@ -75,9 +77,9 @@ const Foods = () => {
</div>
<div className="flex flex-col gap-[20px] px-[16px] py-[12px]">
{Array.isArray(filteredFoods) &&
filteredFoods.map((item) => (
filteredFoods.map((item, index) => (
<FoodCard
key={item.food_id}
key={`${item.food_id}-${index}`}
id={item.food_id}
name={item.food_name}
tag={mapTags(item)}
Expand Down
8 changes: 4 additions & 4 deletions src/pages/fti/Fti.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const Fti = () => {
};
return (
<div className="flex flex-col items-center px-[16px]">
<img className="mt-[55px]" src="/images/ftiStart.png" />
<p className="mt-[75px] text-[26px]">숨은 식탐 DNA 분석해볼래? 🧬🍕</p>
<img className="mt-[55px] xs:mt-[25px]" src="/images/ftiStart.png" />
<p className="mt-[75px] text-[26px] font-semibold xs:mt-[20px] xs:text-[20px]">숨은 식탐 DNA 분석해볼래? 🧬🍕</p>
<p className="mt-[16px] text-center">
3분만 투자하면 너의 진짜 맛잘알 지수가 나온다고! <br /> 이 초간단 테스트로 알아보자!
</p>
<p className="mt-[40px]">솔직하게 답하고 너의 숨겨진 식욕 본능을 깨워봐! 🍽️💥</p>
<Button buttonSize="normal" bgColor="filled" className="mt-[132px] h-[48px]" onClick={handleStart}>
<p className="mt-[40px] xs:mt-[20px]">솔직하게 답하고 너의 숨겨진 식욕 본능을 깨워봐! 🍽️💥</p>
<Button buttonSize="normal" bgColor="filled" className="mt-[132px] h-[48px] xs:mt-[60px]" onClick={handleStart}>
<span className="font-bold">시작하기</span>
</Button>
</div>
Expand Down
168 changes: 92 additions & 76 deletions src/pages/fti/FtiResultId.tsx
Original file line number Diff line number Diff line change
@@ -1,108 +1,124 @@
import { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import Button from '../../components/common/Button';
import { getFtiType } from '../../api/apis/fti';
import { useEffect } from 'react';
import { shareWeb, shareKakao } from '../../utils/shareUtils';
import { getCookie } from '../../utils/cookie';

declare global {
interface Window {
Kakao: any;
}
}

interface Description {
start: { text: string; people: string };
typeDescription: string;
characteristics: string[];
title: { title: string; text: string };
}

const { Kakao } = window;

const FtiResultId = () => {
const navigate = useNavigate();
const location = useLocation();
const { ftiType, uuid } = location.state || {};
const { ftiType, ftiImage, description } = location.state || {};

const [parsedDescription, setParsedDescription] = useState<Description | null>(null);

const realUrl = 'https://www.babpiens.com/fti';

const getFtiData = async () => {
try {
const data = await getFtiType(uuid);
console.log('FTI type:', data);
} catch (error) {
console.error('Failed to get FTI type:', error);
}
};
const parseDescription = (desc: { [key: string]: string }[]): Description => {
const startText = desc[0]['시작'];
const parts = startText.split('\n').map((str) => str.trim());
const text = parts.slice(0, -1).join('\n');
const people = parts[parts.length - 1];

const shareWeb = () => {
if (navigator.share) {
navigator
.share({
title: 'FTI검사 너도 받아볼래?',
text: 'FTI검사하고 음식 추천까지! 완전 럭키비키잖아~🍀',
url: 'https://www.babpiens.com/fti',
})
.then(() => console.log('Successful share'))
.catch((error) => console.log('Error sharing', error));
} else {
alert('Web Share API is not supported in your browser.');
}
};
const typeDescription = desc[1]['유형설명'] || desc[1]['유형 설명'];

const shareKakao = () => {
if (Kakao) {
Kakao.Share.sendDefault({
objectType: 'feed',
content: {
title: 'FTI검사 너도 받아볼래?',
description: 'FTI검사하고 음식 추천까지! 완전 럭키비키잖아~🍀',
imageUrl: '/images/babpience_logo2.png',
link: {
mobileWebUrl: realUrl,
},
},
buttons: [
{
title: '나도 테스트 하러가기',
link: {
mobileWebUrl: realUrl,
},
},
],
});
} else {
console.error('Kakao object is not available.');
}
const characteristicsText = desc[2]['특징'];
const characteristics = characteristicsText.split('\n').map((str) => str.trim().replace('- ', ''));

const titleKey = Object.keys(desc[3])[0];
const titleText = desc[3][titleKey];

return {
start: { text, people },
typeDescription,
characteristics,
title: { title: titleKey, text: titleText },
};
};

useEffect(() => {
console.log('FTI type:', ftiType);
if (description) {
const parsed = parseDescription(description);
setParsedDescription(parsed);
console.log('Parsed description:', parsed);
}
if (Kakao) {
Kakao.cleanup();
Kakao.init(import.meta.env.VITE_APP_KAKAO_MAP_KEY);
console.log(Kakao.isInitialized());
} else {
console.error('Kakao object is not available.');
}
getFtiData();
}, []);
console.log(ftiImage);
}, [description]);

const handleButtonClick = () => {
const refreshToken = getCookie('refresh');
if (refreshToken) {
navigate('/flavor');
} else {
navigate('/signin');
}
};

return (
<div className="flex w-full flex-col items-center px-[16px]">
<div className="mt-[20px]">
<p className="h-[40px] text-[20px]">당신의 음식 유형</p>
<p>걸어다니는 생생 정보통</p>
<div>
<img src={`//${ftiImage}`} alt="FTI Result" className="rounded-[4px]" />
<p className="mt-[5px] text-center text-[10px] text-[#666666]">길게 눌러서 이미지를 저장해주세요.</p>
</div>
<div>이미지</div>
<div>텍스트</div>
<div className="mt-[96px] flex flex-col items-center">

{parsedDescription && (
<div className="mt-[5px]">
<p className="mt-[40px]">{parsedDescription.start.text}</p>
<p className="mt-[10px] text-[14px] text-[#666666]">{parsedDescription.start.people}</p>

<p className="mt-[30px]">{parsedDescription.typeDescription}</p>

<h3 className="mt-[30px] font-semibold">특징</h3>
<ul className="mt-[5px]">
{parsedDescription.characteristics.map((char, index) => (
<li className="mt-[5px] text-[16px]" key={index}>
- {char}
</li>
))}
</ul>
<h2 className="mt-[52px] font-semibold">{`(${parsedDescription.title.title})`}</h2>
<p className="">{parsedDescription.title.text}</p>
</div>
)}
<div className="mt-[96px] flex w-full flex-col items-center">
<p className="text-[26px] font-bold">공유하기</p>
<div className="mt-[28px] flex gap-[16px]">
<img src="/images/kakaotalk.png" alt="카카오톡 공유" onClick={shareKakao} />
<img src="/images/insta.png" alt="인스타그램 공유" onClick={shareWeb} className="cursor-pointer" />
<img src="/images/snsX.png" alt="X 공유" onClick={shareWeb} className="cursor-pointer" />
<img src="/images/share.png" alt="일반 공유" onClick={shareWeb} className="cursor-pointer" />
</div>
<p className="mt-[52px] text-[26px]">음식 탐색 궁합</p>
<div className="mt-[28px] flex gap-[20px]">
<div className="flex flex-col items-center">
<div className="rounded-[8px] bg-black px-[8px] py-[1px] text-[26px] text-white">최고</div>
<p className="my-[16px] text-[20px]">인간 리트리버/수정</p>
<img src="/images/ftiResult.png" alt="" />
</div>
<div className="flex flex-col items-center">
<div className="rounded-[8px] bg-black px-[8px] py-[1px] text-[26px] text-white">최악</div>
<p className="my-[16px] text-[20px]">나사빠진 도라에몽/수정</p>
<img src="/images/ftiResult.png" alt="" />
</div>
<img src="/images/kakaotalk.png" alt="카카오톡 공유" onClick={() => shareKakao(Kakao, realUrl)} />
<img
src="/images/insta.png"
alt="인스타그램 공유"
onClick={() => shareWeb(realUrl)}
className="cursor-pointer"
/>
<img src="/images/snsX.png" alt="X 공유" onClick={() => shareWeb(realUrl)} className="cursor-pointer" />
<img src="/images/share.png" alt="일반 공유" onClick={() => shareWeb(realUrl)} className="cursor-pointer" />
</div>
<Button bgColor="filled" buttonSize="normal" className="mb-[32px] mt-[24px] h-[48px]">
<Button
bgColor="filled"
buttonSize="normal"
className="mb-[32px] mt-[58px] h-[48px]"
onClick={handleButtonClick}>
<p className="text-[16px] font-bold">입맛 검사하고 메뉴 추천받기</p>
</Button>
</div>
Expand Down
Loading

0 comments on commit ea65561

Please sign in to comment.