Skip to content

Commit

Permalink
feat: 로딩페이지 ui (TEAM-CLIP#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
NeoSelf1 committed Aug 22, 2024
1 parent 2732993 commit 2d553bd
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 118 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
"lint": "next lint"
},
"dependencies": {
"axios": "^1.7.4",
"next": "14.1.2",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.3.0",
"react-range": "^1.10.0"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
22 changes: 22 additions & 0 deletions src/app/api/apis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import axios from 'axios';

interface SubmitFormData {
phone_number: string;
prefer_style: string;
}

export const submitForm = async (data: SubmitFormData): Promise<void> => {
try {
console.log(data);
const response = await axios.post(
'https://api.chiksnap.site/recommend',
data,
);

if (response.status !== 200) {
throw new Error('전송 실패');
}
} catch (error) {
throw new Error('실패: ' + error);
}
};
95 changes: 57 additions & 38 deletions src/app/photographer/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
'use client';

import React from 'react';
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 ArrowBack from '@/data/arrowLeft.svg';
import Loading from '@/components/Loading';

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

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

return () => clearTimeout(timer);
}, []);

const backFunction = () => {
router.back();
};

const searchParams = useSearchParams();
const type = searchParams.get('type');
const moods = searchParams.get('moods');
Expand All @@ -23,8 +35,12 @@ const RecommendedPhotographers = () => {
.sort(() => Math.random() - 0.5)
.slice(0, 3);

if (isLoading) {
return <Loading />; // 로딩 중일 때 로딩 컴포넌트 표시
}

return (
<div className="relative flex flex-col mx-[1rem] mt-[3.5rem] lg:h-screen md:h-screen sm:h-screen">
<div className="relative flex flex-col mx-[1rem] mt-[3.5rem]">
<div className="cursor-pointer" onClick={backFunction}>
<div className="flex w-[1.5rem] h-[1.5rem] my-[0.75rem]">
<Image src={ArrowBack} alt="Back" objectFit="cover" />
Expand All @@ -34,29 +50,29 @@ const RecommendedPhotographers = () => {
칙스냅에서 추천드리는 작가예요!
</h2>
<h3 className="body-3 text-gray-500 mb-[1.75rem]">
아래 작가분들은 여러분의 선택을 기반으로 칙스냅에서 추천드리는
작가님이에요. 자세히 보기를 통해 작가님의 정보를 확인하고 그리던 사진을
촬영해요
선택하신 분위기를 기반으로
<br />
칙스냅에서 추천드리는 작가님들이에요.
</h3>
<div className="flex flex-col gap-[0.62rem]">
<div className="flex flex-col gap-[0.62rem] mb-[5rem]">
{selectedPhotographers.map((photographer) => (
<div
key={photographer.id}
className="flex flex-col w-full bg-gray-50 p-[0.75rem] rounded-[0.5rem]"
className="flex flex-col w-full bg-gray-50 hover:bg-gray-100 p-[0.75rem] rounded-[0.5rem] cursor-pointer"
>
<a href={`https://www.instagram.com/${photographer.instagramId}/`}>
<div className="flex w-full mb-[1rem] rounded-[0.25rem]">
<div className="flex relative w-[3.38rem] h-[3.38rem] mr-[0.62rem]">
<Image
src={photographer.profileImg}
alt={photographer.name}
width={54}
height={54}
objectFit="cover"
className="rounded-lg transition-transform duration-300 ease-in-out hover:scale-110"
/>
</div>
<div className="flex flex-col w-full justify-center gap-[0.37rem]">
<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}
alt={photographer.name}
width={54}
height={54}
objectFit="cover"
className="rounded-lg transition-transform duration-300 ease-in-out hover:scale-110"
/>
</div>
<div className="flex items-center gap-[0.5rem]">
<span className="body-1 text-gray-900">
{photographer.name}
Expand All @@ -65,19 +81,19 @@ const RecommendedPhotographers = () => {
{`@${photographer.instagramId}`}
</span>
</div>
<div className="flex items-center gap-[0.5rem]">
<div className="caption px-[0.5rem] py-[0.25rem] bg-gray-200 rounded-[0.25rem]">
{photographer.price}
</div>
{photographer.services.map((value, index) => (
<div
key={index}
className="caption px-[0.5rem] py-[0.25rem] bg-white rounded-[0.25rem]"
>
{value}
</div>
))}
</div>
<div className="flex items-center gap-[0.25rem] mb-[0.62rem]">
<div className="caption px-[0.5rem] py-[0.25rem] bg-gray-200 rounded-[0.25rem]">
{photographer.price}
</div>
{photographer.services.map((value, index) => (
<div
key={index}
className="caption px-[0.5rem] py-[0.25rem] bg-white rounded-[0.25rem]"
>
{value}
</div>
))}
</div>
</div>
<div className="flex gap-[0.5rem]">
Expand All @@ -97,13 +113,16 @@ const RecommendedPhotographers = () => {
</div>
))}
</div>
<div className="flex">
<Link
href={'/request-custom'}
className={'btn-default body-3 mt-[2rem] mb-[1rem]'}
>
맞춤형 작가 요청하기
</Link>

<div className="fixed bottom-0 left-0 right-0 flex justify-center py-4 cursor-pointer">
<div className="flex w-full max-w-md mx-4">
<Link
href={'/request-custom'}
className={'btn-default body-3 w-full lg:mx-4 md:mx-4 sm:mx-4'}
>
맞춤형 작가 요청하기
</Link>
</div>
</div>
</div>
);
Expand Down
62 changes: 47 additions & 15 deletions src/app/request-custom/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use client';

import { ChangeEvent, useState } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import ArrowBack from '@/data/arrowLeft.svg';
import { useRouter } from 'next/navigation';
import { submitForm } from '../api/apis';

const RequestCustom = () => {
const router = useRouter();
Expand All @@ -13,16 +13,43 @@ const RequestCustom = () => {
};

const [text, setText] = useState<string>('');
const [phoneNumber, setPhoneNumber] = useState<string>('');
const [loading, setLoading] = useState<boolean>(false);

const handleTextChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setText(e.target.value);
};

const handlePhoneNumberChange = (e: ChangeEvent<HTMLInputElement>) => {
setPhoneNumber(e.target.value);
};

const isOverLimit = text.length > 600;
const isTextEntered = text.length > 0;
const isPhoneNumberEntered = phoneNumber.trim().length > 0;

const handleSubmit = async () => {
console.log(phoneNumber);
console.log(text);
if (!isPhoneNumberEntered) return;

setLoading(true);

try {
await submitForm({ phone_number: phoneNumber, prefer_style: text });

alert('요청이 성공적으로 전송되었습니다.');
router.push('/');
} catch (error) {
console.error('실패: ', error);
alert('요청 전송에 실패했습니다. 다시 시도해주세요.');
} finally {
setLoading(false);
}
};

return (
<div className="relative flex flex-col mx-[1rem] mt-[3.5rem] lg:h-screen md:h-screen sm:h-screen">
<div className="relative flex flex-col mx-[1rem] mt-[3.5rem]">
<div className="cursor-pointer" onClick={backFunction}>
<div className="flex w-[1.5rem] h-[1.5rem] my-[0.75rem]">
<Image src={ArrowBack} alt="Back" objectFit="cover" />
Expand All @@ -44,6 +71,8 @@ const RequestCustom = () => {
<input
type="text"
placeholder="XXX - XXXX - XXXX"
value={phoneNumber}
onChange={handlePhoneNumberChange}
className="w-full h-[3.125rem] px-[0.875rem] bg-gray-50 rounded-lg body-1 placeholder-gray-300
hover:bg-gray-100 focus:bg-gray-100 focus:border-gray-200 focus:ring-0 focus:outline-none
border border-transparent transition-colors duration-200
Expand All @@ -56,14 +85,15 @@ const RequestCustom = () => {
<div className="mb-[1.75rem]">
<textarea
placeholder="예) 따뜻한 분위기의 숲속에서 찍는 스타일, "
className={`flex w-full min-h-[13rem] p-[0.875rem] rounded-lg body-3 placeholder-gray-300 resize-none
className={`flex w-full min-h-[13rem] p-[0.875rem] rounded-lg body-3 placeholder-gray-300 resize-none bg-gray-50
${
isOverLimit
? 'border-red-100 focus:outline-red-100'
: 'border-gray-200'
}
${isTextEntered ? 'bg-gray-100' : 'bg-gray-50'}
transition-colors duration-200
focus:bg-gray-100
hover:bg-gray-100 focus:outline-none focus:outline-1 focus:outline-gray-200`}
style={{ outlineOffset: '0px' }}
value={text}
Expand All @@ -80,18 +110,20 @@ const RequestCustom = () => {
</div>
</div>
</div>
<div className="flex">
<Link
href={'/'}
// href={{
// pathname: '/photographer',
// query: { type, moods: selectedMoods.join(',') },
// }}
// aria-disabled={selectedMoods.length !== 3}
className={'btn-primary body-3 mb-[1rem]'}
>
요청하기
</Link>
<div className="fixed bottom-0 left-0 right-0 flex justify-center py-4 cursor-pointer">
<div className="flex w-full max-w-md mx-4">
<button
onClick={handleSubmit}
disabled={!isPhoneNumberEntered || loading}
className={`body-3 w-full text-center py-3 rounded-lg transition-colors duration-200 lg:mx-4 md:mx-4 sm:mx-4 ${
isPhoneNumberEntered
? 'btn-primary'
: 'btn-default pointer-events-none'
} ${loading ? 'opacity-50' : ''}`}
>
요청하기
</button>
</div>
</div>
</div>
);
Expand Down
35 changes: 30 additions & 5 deletions src/app/request-notification/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
'use client';

import { ChangeEvent, useState } from 'react';
import { useState } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import Close from '@/data/close.svg';
import Instagram from '@/data/instagram.svg';
import { useRouter } from 'next/navigation';

const RequestNotification = () => {
const router = useRouter();
const backFunction = () => {
router.back();
};

const [phoneNumber, setPhoneNumber] = useState<string>('');

const handlePhoneNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setPhoneNumber(e.target.value);
};

const isPhoneNumberEntered = phoneNumber.trim().length > 0;

return (
<div className="relative flex flex-col mx-[1rem] pt-[3.5rem] h-screen">
<Link href={'/'} className="flex justify-end cursor-pointer">
<div className="flex justify-end cursor-pointer" onClick={backFunction}>
<div className="flex w-[1.5rem] h-[1.5rem] my-[0.75rem]">
<Image src={Close} alt="Back" objectFit="cover" />
</div>
</Link>
</div>
<h2 className="title-1 mt-[0.62rem] mb-[0.25rem]">
칙스냅이 오픈되면, 알려드릴게요!
</h2>
Expand All @@ -34,6 +48,8 @@ const RequestNotification = () => {
<input
type="text"
placeholder="XXX - XXXX - XXXX"
value={phoneNumber}
onChange={handlePhoneNumberChange}
className="w-full h-[3.125rem] px-[0.875rem] bg-gray-50 rounded-lg body-1 placeholder-gray-300
hover:bg-gray-100 focus:bg-gray-100 focus:border-gray-200 focus:ring-0 focus:outline-none
border border-transparent transition-colors duration-200
Expand All @@ -45,13 +61,22 @@ const RequestNotification = () => {
<a href={`https://www.instagram.com/chik_snap/`} className="w-1/2">
<button className="btn-default flex justify-center items-center w-full body-3 rounded-lg gap-[0.25rem]">
<div className="flex w-[1.5rem] h-[1.5rem]">
<Image src={Instagram} alt="Back" objectFit="cover" />
<Image src={Instagram} alt="Instagram" objectFit="cover" />
</div>
칙스냅에 문의하기
</button>
</a>
<Link href="/" className="flex-grow">
<button className="btn-primary w-full body-3">신청하기</button>
<button
className={`body-3 w-full py-3 rounded-lg transition-colors duration-200 ${
isPhoneNumberEntered
? 'btn-primary body-3 text-white'
: 'btn-default body-3 cursor-not-allowed'
}`}
disabled={!isPhoneNumberEntered}
>
신청하기
</button>
</Link>
</div>
</div>
Expand Down
Loading

0 comments on commit 2d553bd

Please sign in to comment.