Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 사진작가추천 알고리즘 추가 #10

Merged
merged 5 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['picsum.photos'], // 허용할 외부 이미지 도메인 추가
domains: [
'chik.s3.ap-northeast-2.amazonaws.com',
'scontent-gmp1-1.cdninstagram.com',
], // 허용할 외부 이미지 도메인 추가
},
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function RootLayout({
}>) {
return (
<html lang="ko">
<body className={`${pretendard.className} bg-gray-100 overflow-x-hidden`}>
<body className={`${pretendard.className} bg-white overflow-x-hidden`}>
<ClipContainer>
<main className="flex-grow overflow-y-auto">{children}</main>
</ClipContainer>
Expand Down
11 changes: 7 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,31 @@ const Home = () => {
className="pointer-events-none"
/>
</div>
{/* 배경 그라데이션 */}
<div className="absolute inset-0 z-10 bg-gradient-to-t from-black/80 via-black/70 to-transparent"></div>

<div className="absolute inset-0 z-10 bg-gradient-to-t from-black/80 via-black/70 to-transparent" />
<div className="relative z-20 h-full flex flex-col justify-between">
<div className="pl-[1.25rem]">
<h1 className="body-2 mt-[6.94rem] mb-[0.64rem] text-white">
순간을 Chik다,
<br />
칙스냅
</h1>

<div className="w-[6.3125rem] h-[0.125rem] rounded-[12.5rem] bg-white/40" />
</div>

<div className="flex flex-col">
<div className="pl-[1.25rem]">
<h1 className="heading text-white mb-[1rem]">
스냅 작가님을
<br />
찾고 있으신가요?
</h1>

<p className="body-2 text-white mb-[3.25rem]">
나에게 맞는 스냅 작가님을 찾기
나만을 위한, 내가 원하는 스타일에 맞는
<br />
어려우셨다면 저희가 찾아드릴게요!
작가를 칙스냅에서 찾아보세요
</p>
</div>

Expand Down
134 changes: 99 additions & 35 deletions src/app/photographer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,92 @@
import React, { useEffect, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { useRouter, useSearchParams } from 'next/navigation';
import { photographers_mu } from '@/data/database';
import { useSearchParams } from 'next/navigation';
import Loading from '@/components/Loading';
import { photoData, photographerData, snapTypeChoice } from '@/data/database';
import { Photographer } from '@/types';

const RecommendedPhotographers = () => {
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();

useEffect(() => {
const timer = setTimeout(() => {
setIsLoading(false);
}, 1500); // 2.5초

return () => clearTimeout(timer);
}, []);
const [data, setData] = useState<any>([]);

const searchParams = useSearchParams();
const type = searchParams.get('type');
const moods = searchParams.get('moods');

//type, price, moods 정보로 작가 추리는 로직 여기서 구현하고 바로 띄우면 될듯.
const processRecommendation = async () => {
const types = searchParams
.get('type')
?.split(',')
.map((item: string) => +item);
const moods = searchParams
.get('moods')
?.split(',')
.map((id: string) => photoData.find((item) => item.id === +id)?.mood)
.sort();
if (!types || !moods) return;

const filteredPhotographerByType = photographerData.filter((item) =>
types.some((type: any) => item.types.includes(type)),
);

const photoMoodMap = new Map(
photoData.map((photo) => [photo.id, photo.mood]),
);

const photographerMoodCounts = filteredPhotographerByType.map(
(photographer) => {
// 모든 사진작가들에 대해,
const moodCounts = new Map<number, number>();
for (const imageId of photographer.works) {
//순회하는 사진작가 작품 이미지의 무드를
const mood = photoMoodMap.get(imageId);
if (mood !== undefined) {
// moodId,
moodCounts.set(mood, (moodCounts.get(mood) || 0) + 1);
}
}
return { photographer, moodCounts };
},
);

const moodSortedPhotographers = moods.map((mood) =>
[...photographerMoodCounts]
.sort(
(a, b) =>
(b.moodCounts.get(mood!) || 0) - (a.moodCounts.get(mood!) || 0),
)
.map((item) => item.photographer),
);

const selectedPhotographers = new Set<Photographer>();
const moodIndices = new Array(moods.length).fill(0);

while (selectedPhotographers.size < 3) {
for (let i = 0; i < moods.length; i++) {
if (moodIndices[i] < moodSortedPhotographers[i].length) {
const photographer = moodSortedPhotographers[i][moodIndices[i]];
selectedPhotographers.add(photographer);
moodIndices[i]++;
if (selectedPhotographers.size === 3) break;
}
}
if (
moodIndices.every(
(index, i) => index === moodSortedPhotographers[i].length,
)
)
break;
}
console.log(Array.from(selectedPhotographers));
setData(Array.from(selectedPhotographers));
};

// 배열을 랜덤하게 섞고 처음 3명의 작가만 선택
const selectedPhotographers = [...photographers_mu]
.sort(() => Math.random() - 0.5)
.slice(0, 3);
useEffect(() => {
console.log('hello', data);
if (data.length === 0) {
processRecommendation();
}
setIsLoading(false);
}, []);

if (isLoading) {
return <Loading />; // 로딩 중일 때 로딩 컴포넌트 표시
Expand All @@ -45,20 +105,20 @@ const RecommendedPhotographers = () => {
</h3>

<div className="flex flex-col gap-[0.62rem]">
{selectedPhotographers.map((photographer) => (
{data.map((photographer: Photographer) => (
<div
key={photographer.id}
className="flex flex-col w-full bg-gray-50 hover:bg-gray-100 p-[0.75rem] rounded-[0.5rem] cursor-pointer"
>
<Link
target={'_blank'}
href={`https://www.instagram.com/${photographer.instagramId}`}
href={`https://www.instagram.com/${photographer.instagram_id}`}
>
<div className="flex flex-col w-full justify-center">
<div className="flex w-full mb-[0.63rem]">
<div className="flex relative w-[2.25rem] h-[2.25rem] mr-[0.62rem] rounded-[0.25rem]">
<Image
src={photographer.profileImg}
src={photographer.profile_image_url}
alt={photographer.name}
width={54}
height={54}
Expand All @@ -73,7 +133,7 @@ const RecommendedPhotographers = () => {
</span>

<span className="caption text-gray-600">
{`@${photographer.instagramId}`}
{`@${photographer.instagram_id}`}
</span>
</div>
</div>
Expand All @@ -82,28 +142,32 @@ const RecommendedPhotographers = () => {
<div className="caption px-[0.5rem] py-[0.25rem] bg-gray-200 rounded-[0.25rem]">
{photographer.price}
</div>
{photographer.services.map((value, index) => (
{photographer.types.map((typeId, index) => (
<div
key={index}
className="caption px-[0.5rem] py-[0.25rem] bg-white rounded-[0.25rem]"
>
{value}
{snapTypeChoice[typeId].title}
</div>
))}
</div>
</div>
<div className="flex gap-[0.5rem]">
{photographer.workImages.map((value, index) => (
<div key={index} className="relative w-1/3 h-[8.5rem]">
<Image
src={value}
alt="example image"
layout="fill"
objectFit="cover"
className="rounded-[0.25rem]"
/>
</div>
))}
{photographerData
.find((item) => item.id === photographer.id)
?.works.slice(0, 3)
.map((imageId, index) => (
<div key={index} className="relative w-1/3 h-[8.5rem]">
<Image
src={
photoData.find((item) => item.id === imageId)?.url!
}
alt="example image"
layout="fill"
className="rounded-[0.25rem] object-cover"
/>
</div>
))}
</div>
</Link>
</div>
Expand Down
13 changes: 9 additions & 4 deletions src/app/select-mood/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
import { useState } from 'react';
import Link from 'next/link';
import { useSearchParams } from 'next/navigation';
import { group1, group2, group3 } from '@/data/database';
import MoodImageGroup from '@/components/MoodImageGroup';
import {
images_couple,
images_personal,
images_wedding,
} from '@/data/database';

const SelectMood = () => {
const searchParams = useSearchParams();
const type = searchParams.get('type');

const [selectedMoods, setSelectedMoods] = useState<number[]>([]);

const toggleMood = (id: number) => {
Expand Down Expand Up @@ -41,17 +46,17 @@ const SelectMood = () => {
<div className="flex-grow px-4 mt-28 mb-20">
<div className="flex flex-row space-x-1 pb-4">
<MoodImageGroup
images={group1}
images={images_personal}
selectedMoods={selectedMoods}
toggleMood={toggleMood}
/>
<MoodImageGroup
images={group2}
images={images_couple}
selectedMoods={selectedMoods}
toggleMood={toggleMood}
/>
<MoodImageGroup
images={group3}
images={images_wedding}
selectedMoods={selectedMoods}
toggleMood={toggleMood}
/>
Expand Down
11 changes: 0 additions & 11 deletions src/app/select-price/loading.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions src/app/select-price/page.tsx

This file was deleted.

Loading