Skip to content

Commit

Permalink
Merge pull request #75 from cau-likelion-org/feat/#74
Browse files Browse the repository at this point in the history
feat: ํ”„๋กœ์ ํŠธ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • Loading branch information
cjy3458 authored Jan 27, 2025
2 parents cb2e6ce + 4a7c0f5 commit 0e1e98d
Show file tree
Hide file tree
Showing 12 changed files with 336 additions and 126 deletions.
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const nextConfig = {
'd1sgygn8l0lfd5.cloudfront.net',
'dcpshnp4boilw.cloudfront.net',
'd1e39uzon1ymuo.cloudfront.net',
'likelion13bucket.s3.amazonaws.com',
],
},
webpack(config) {
Expand Down
17 changes: 17 additions & 0 deletions src/apis/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import axios from 'axios';
import { url } from '.';
import { getAuthAxios } from './authAxios';
import { IToken } from '@utils/state';
import { IProjectDetail, UploadData } from '@@types/request';

// export function postGalleryData(data: IProjectDetail, token: IToken) {
// const authAxios = getAuthAxios(token);
// return authAxios.post(`/api/admin/postProject`, {
// data,
// });
// }

export async function postGalleryData(data: FormData) {
const result = await axios.post(`${process.env.NEXT_PUBLIC_API_KEY}/api/project`, data);
return result;
}
10 changes: 4 additions & 6 deletions src/apis/gallery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import axios from 'axios';
import { url } from '.';

export async function getGalleries() {
const data = await axios.get<ResponseData<ArchivingArrayType<IGalleryData>>>(
`${url}/api/gallery`,
).then(res => res.data.data);
const data = await axios
.get<ResponseData<ArchivingArrayType<IGalleryData>>>(`${url}/api/gallery`)
.then((res) => res.data.data);
return data;
}

export async function getGalleryDetail(id: string) {
const data = await axios.get<ResponseData<IGalleryDetail>>(
`${url}/api/gallery/${id}`,
).then(res => res.data.data);
const data = await axios.get<ResponseData<IGalleryDetail>>(`${url}api/gallery/${id}`).then((res) => res.data.data);
return data;
}
5 changes: 2 additions & 3 deletions src/apis/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export async function getProjects() {
}

export async function getProjectDetail(id: string) {
const data = await axios
.get<ResponseData<IProjectDetail>>(`${url}/api/project/${id}`)
.then((res) => res.data.data);
const data = await axios.get<ResponseData<IProjectDetail>>(`${url}/api/project/${id}`).then((res) => res.data.data);
console.log(data);
return data;
}
144 changes: 144 additions & 0 deletions src/components/admin/PostAdmin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { IProjectDetail, UploadData } from '@@types/request';
import React, { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { postGalleryData } from 'src/apis/admin';
import { token } from '@utils/state';
import useInput from 'src/hooks/useInput';
import styled from 'styled-components';

const PostAdmin = () => {
// Input ์ƒํƒœ ๊ด€๋ฆฌ
const [title, onChangeTitle] = useInput('');
const [subTitle, onChangeSubTitle] = useInput('');
const [devStack, onChangeDevStack] = useInput('');
const [version, onChangeVersion] = useInput('');
const [teamName, onChangeTeamName] = useInput('');
const [pm, onChangePm] = useInput('');
const [de, onChangeDe] = useInput('');
const [fe, onChangeFe] = useInput('');
const [be, onChangeBe] = useInput('');
const [start, onChangeStart] = useInput('');
const [end, onChangeEnd] = useInput('');
const [description, onChangeDescription] = useInput('');
const [webLink, onChangeWebLink] = useInput('');
const [category, onChangeCategory] = useInput('');
const [thumbnail, setThumbnail] = useState<File | null>(null);
const [images, setImages] = useState<File[]>([]);
const a: string = 'aaa';
// ํŒŒ์ผ ์—…๋กœ๋“œ ํ•ธ๋“ค๋Ÿฌ
const handleThumbnailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
setThumbnail(e.target.files[0]);
}
};

const handleImagesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
// e.target.files๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด Array.from()์œผ๋กœ ํŒŒ์ผ์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ถ”๊ฐ€
setImages((prevImages) => [
...prevImages,
...Array.from(e.target.files as FileList), // FileList๋กœ ๋ช…์‹œ์  ํƒ€์ž… ์บ์ŠคํŒ…
]);
}
};

// ์ œ์ถœ ํ•ธ๋“ค๋Ÿฌ
const handleSubmit = async () => {
if (!thumbnail || images.length === 0) {
alert('์ธ๋„ค์ผ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋ชจ๋‘ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.');
return;
}

const formData = new FormData();

formData.append('title', title);
formData.append('subtitle', subTitle);
formData.append('dev_stack', devStack);
formData.append('version', version);
formData.append('team_name', teamName);
formData.append('start_date', start);
formData.append('end_date', end);
formData.append('description', description);
formData.append('category', category);
formData.append('login_email', 'adsf'); // ๋กœ๊ทธ์ธ ์ด๋ฉ”์ผ์€ ์ž„์‹œ ๋ฐ์ดํ„ฐ
formData.append(
'team_member',
JSON.stringify({
pm: pm.split(','),
design: de.split(','),
frontend: fe.split(','),
backend: be.split(','),
}),
);

formData.append(
'link',
JSON.stringify({
github: 'fadsf',
youtube: 'ffasd',
web: webLink,
}),
);

// ์ธ๋„ค์ผ ํŒŒ์ผ ์ถ”๊ฐ€
formData.append('thumbnail', thumbnail);

// ์ด๋ฏธ์ง€ ๋ฐฐ์—ด ์ถ”๊ฐ€
images.forEach((image) => {
formData.append('images', image);
});

try {
const result = await postGalleryData(formData);
console.log(result);
alert('์—…๋กœ๋“œ ์„ฑ๊ณต');
} catch (error) {
console.error(error);
alert('์—…๋กœ๋“œ ์‹คํŒจ');
}
};

return (
<Wrapper>
<h1>ํ”„๋กœ์ ํŠธ ์—…๋กœ๋“œ</h1>
<input type="text" value={title} onChange={onChangeTitle} placeholder="์ œ๋ชฉ" />
<input type="text" value={subTitle} onChange={onChangeSubTitle} placeholder="๋ถ€์ œ๋ชฉ" />
<input type="text" value={devStack} onChange={onChangeDevStack} placeholder="๊ฐœ๋ฐœ ์Šคํƒ" />
<input type="text" value={version} onChange={onChangeVersion} placeholder="๋ฒ„์ „" />
<input type="text" value={teamName} onChange={onChangeTeamName} placeholder="ํŒ€ ์ด๋ฆ„" />
<input type="text" value={pm} onChange={onChangePm} placeholder="PM" />
<input type="text" value={de} onChange={onChangeDe} placeholder="๋””์ž์ธ" />
<input type="text" value={fe} onChange={onChangeFe} placeholder="ํ”„๋ก ํŠธ์—”๋“œ" />
<input type="text" value={be} onChange={onChangeBe} placeholder="๋ฐฑ์—”๋“œ" />
<input type="string" value={start} onChange={onChangeStart} placeholder="์‹œ์ž‘ ๋‚ ์งœ" />
<input type="string" value={end} onChange={onChangeEnd} placeholder="์ข…๋ฃŒ ๋‚ ์งœ" />
<input type="string" onChange={onChangeDescription} placeholder="์„ค๋ช…"></input>
<input type="url" value={webLink} onChange={onChangeWebLink} placeholder="์›น ๋งํฌ" />
<input type="text" value={category} onChange={onChangeCategory} placeholder="์นดํ…Œ๊ณ ๋ฆฌ" />

<Title>ํ”„๋กœ์ ํŠธ ์ธ๋„ค์ผ ์ด๋ฏธ์ง€</Title>
<input type="file" accept="image/*" onChange={handleThumbnailChange} />

<Title>ํ”„๋กœ์ ํŠธ ์ด๋ฏธ์ง€</Title>
<input type="file" accept="image/*" multiple onChange={handleImagesChange} />

<button onClick={handleSubmit}>์—…๋กœ๋“œํ•˜๊ธฐ</button>
</Wrapper>
);
};

export default PostAdmin;

const Wrapper = styled.div`
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;
`;

const Title = styled.div`
font-size: 2rem;
font-weight: bold;
`;
15 changes: 3 additions & 12 deletions src/components/archiving/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@ const Card = ({ id, thumbnail, title, dev_stack, category, link, subtitle }: ICa
<Link href={`${link}/${id}`}>
<Wrapper>
<ImageWrapper>
<CustomImage
src={thumbnail}
alt="์ธ๋„ค์ผ"
layout="fill"
objectFit="contain"
objectPosition="center"
/>
<CustomImage src={thumbnail} alt="์ธ๋„ค์ผ" layout="fill" objectFit="contain" objectPosition="center" />
</ImageWrapper>
<TextWrapper>
<Category link={link}>{category}</Category>
Expand All @@ -36,8 +30,7 @@ const Card = ({ id, thumbnail, title, dev_stack, category, link, subtitle }: ICa
};

export default Card;
const CustomImage = styled(Image)`
`;
const CustomImage = styled(Image)``;

const Wrapper = styled.div`
border-radius: 20px;
Expand Down Expand Up @@ -98,9 +91,8 @@ const TextWrapper = styled.div`
@media (min-width: 330px) and (max-width: 444px) {
width: 180px;
}
`;
const Category = styled.div<{ link: string; }>`
const Category = styled.div<{ link: string }>`
border-radius: 25px;
border: ${(props) => (props.link === '/gallery' ? 'none' : `1px solid ${GreyScale.default}`)};
display: flex;
Expand Down Expand Up @@ -135,5 +127,4 @@ const ProjectDesc = styled.div`
@media (max-width: 1300px) {
font-size: 10px;
}
`;
12 changes: 7 additions & 5 deletions src/components/gallery/GalleryListSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { useQuery } from 'react-query';
import { getGalleries } from 'src/apis/gallery';
import styled from 'styled-components';

const GalleryListSection = ({ staticData }: { staticData: ArchivingArrayType<IGalleryData>; }) => {
const GalleryListSection = ({ staticData }: { staticData: ArchivingArrayType<IGalleryData> }) => {
const { data, isLoading } = useQuery<ArchivingArrayType<IGalleryData>>(['galleries'], getGalleries);

return (
<Wrapper>
{sortArchivingListDesc(isLoading ? staticData : (data as ArchivingArrayType<IGalleryData>))!.map(([year, value]) => (
<Archiving archivingType={'gallery'} archivingIndex={year} archivingData={value} key={year} />
))}
{sortArchivingListDesc(isLoading ? staticData : (data as ArchivingArrayType<IGalleryData>))!.map(
([year, value]) => (
<Archiving archivingType={'gallery'} archivingIndex={year} archivingData={value} key={year} />
),
)}
</Wrapper>
);
};
Expand All @@ -24,4 +26,4 @@ const Wrapper = styled.div`
display: flex;
flex-direction: column;
margin: 3rem;
`;
`;
Loading

0 comments on commit 0e1e98d

Please sign in to comment.