Skip to content

Commit

Permalink
Merge pull request #26 from pythonkr/feature/sponsor-detail
Browse files Browse the repository at this point in the history
Feat: 후원사 상세 페이지 작업
  • Loading branch information
jungmir authored Sep 18, 2024
2 parents df8e0b1 + b6d3020 commit 20bd691
Show file tree
Hide file tree
Showing 12 changed files with 10,450 additions and 14,713 deletions.
3 changes: 2 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
REACT_APP_PYCONKR_API=https://api-dev.pycon.kr
# REACT_APP_PYCONKR_API=https://api-dev.pycon.kr
REACT_APP_PYCONKR_API=http://localhost:8888
2 changes: 1 addition & 1 deletion scripts/set_dev.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cp ./.env.dev ./.env || copy .\\env.dev .\\.env
cp ./.env.development ./.env || copy .\\env.development .\\.env
20 changes: 16 additions & 4 deletions src/api/sponsor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@ import { APISponsor, APISponsorBenefit, APISponsorLevel, APISponsorLevelWithSpon
import { Sponsor, SponsorBenefit, SponsorLevel, SponsorLevelWithSponsor } from "models/sponsor"


export function detailSponsor(id: string): Promise<Sponsor> {
return new Promise((resolve, reject) => {
instance.get<APISponsor>(`http://localhost:8888/2024/sponsors/list/${id}/`).then(response => {
resolve(Sponsor.fromAPI(response.data));
}).catch(error => {
console.error(error);
reject(getErrorMessage(error));
})
return;
})
}

export function listSponsorLevels(): Promise<SponsorLevel[]> {
return new Promise((resolve, reject) => {
instance.get<APISponsorLevel[]>("/2024/sponsors/levels").then((response) => {
instance.get<APISponsorLevel[]>("http://localhost:8888/2024/sponsors/levels").then((response) => {
resolve(SponsorLevel.fromAPIs(response.data));
}).catch((error) => {
console.error(error);
Expand All @@ -19,7 +31,7 @@ export function listSponsorLevels(): Promise<SponsorLevel[]> {
export function listSponsors(): Promise<Sponsor[]> {
return new Promise((resolve, reject) => {
instance
.get<APISponsor[]>("/2024/sponsors/list/")
.get<APISponsor[]>("http://localhost:8888/2024/sponsors/list/")
.then((response) => {
resolve(Sponsor.fromAPIs(response.data));
})
Expand All @@ -32,7 +44,7 @@ export function listSponsors(): Promise<Sponsor[]> {
export function listSponsorLevelWithSponsor(): Promise<SponsorLevelWithSponsor[]> {
return new Promise((resolve, reject) => {
instance
.get<APISponsorLevelWithSponsor[]>("/2024/sponsors/levels/with-sponsor/")
.get<APISponsorLevelWithSponsor[]>("http://localhost:8888/2024/sponsors/levels/with-sponsor/")
.then((response) => {
console.log("debug", response);
resolve(SponsorLevelWithSponsor.fromAPIs(response.data));
Expand All @@ -46,7 +58,7 @@ export function listSponsorLevelWithSponsor(): Promise<SponsorLevelWithSponsor[]

export function listSponsorBenefits(): Promise<SponsorBenefit[]> {
return new Promise((resolve, reject) => {
instance.get<APISponsorBenefit[]>("/2024/sponsors/benefits/").then(response => {
instance.get<APISponsorBenefit[]>("http://localhost:8888/2024/sponsors/benefits/").then(response => {
resolve(SponsorBenefit.fromAPIs(response.data));
}).catch(error => {
console.error(error);
Expand Down
1 change: 1 addition & 0 deletions src/components/Footer/SponsorList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const Vertical = styled.div`
`;

const SponsorTableList = styled.div`
width: 80%;
& > div + div {
margin-top: 2rem;
}
Expand Down
6 changes: 4 additions & 2 deletions src/components/Footer/SponsorTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Sponsor } from "models/sponsor";
import { Link } from "react-router-dom";
import React, { useCallback, useEffect, useRef, useState } from "react";
import styled from "styled-components";

Expand All @@ -14,7 +15,9 @@ function SponsorTable({ max, levelName, sponsors, ...rest }: Props) {
<h3>{levelName}</h3>
<div style={{ gridTemplateColumns: `repeat(${max}, 1fr)` }}>
{sponsors.map((sponsor) => (
<img src={sponsor.logo_image} alt={sponsor.name} />
<Link to={`/sponsoring/sponsor/${sponsor.id}`} relative="path">
<img src={sponsor.logo_image} alt={sponsor.name} />
</Link>
))}
</div>
</SponsorCard>
Expand Down Expand Up @@ -42,7 +45,6 @@ const SponsorCard = styled.div`
}
@media only screen and (max-width: 810px) {
display: block;
margin: 1rem;
& > div {
Expand Down
1 change: 1 addition & 0 deletions src/models/api/sponsor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type APISponsorBenefit = {
unit: string;
is_countable: boolean;
offer: Number;
uncountable_offer: string;
}

export type APISponsorLevel = {
Expand Down
3 changes: 3 additions & 0 deletions src/models/sponsor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export class SponsorBenefit {
offer: Number;
unit: string;
is_countable: boolean;
uncountable_offer: string;

private constructor(p: SponsorBenefit) {
this.id = p.id;
Expand All @@ -15,6 +16,7 @@ export class SponsorBenefit {
this.offer = p.offer;
this.unit = p.unit;
this.is_countable = p.is_countable;
this.uncountable_offer = p.uncountable_offer;
}

static fromAPI(d: APISponsorBenefit): SponsorBenefit {
Expand All @@ -25,6 +27,7 @@ export class SponsorBenefit {
offer: d.offer,
unit: d.unit,
is_countable: d.is_countable,
uncountable_offer: d.uncountable_offer,
});
}
static fromAPIs(data: APISponsorBenefit[]): SponsorBenefit[] {
Expand Down
93 changes: 93 additions & 0 deletions src/pages/Sponsor/SponsorDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { SponsorAPI } from "api";
import * as R from "remeda";
import { wrap } from "@suspensive/react";
import React, { useEffect, useState } from "react";
import useTranslation from "utils/hooks/useTranslation";
import { APISponsor } from "models/api/sponsor";
import { useNavigate, useParams } from "react-router";
import styled from "styled-components";
import { useRetrieveSponsorQuery } from "utils/hooks/useAPI";

const SponsorDetail: React.FC<{ sponsor: APISponsor }> = ({ sponsor }) => {
return (
<Vertical>
<H1>{sponsor.name}</H1>
<a href={sponsor.url}>
<img src={sponsor.logo_image} alt={sponsor.name} />
</a>
<H3 dangerouslySetInnerHTML={{ __html: sponsor.desc }}></H3>
</Vertical>
);
};

const SponsorDetailPage = () => {
const t = useTranslation();
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();

if (!(R.isString(id) && !R.isEmpty(id))) {
navigate("/session");
return null;
}

const SponsorDetailWrapper = wrap
.ErrorBoundary({ fallback: <h4>{t("후원사 정보를 불러오는 중 에러가 발생했습니다.")}</h4> })
.Suspense({ fallback: <h4>{t("후원사 정보를 불러오는 중 입니다.")}</h4> })
.on(() => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { data } = useRetrieveSponsorQuery(id);
return <SponsorDetail sponsor={data} />;
});

return (
<Container>
<SponsorDetailWrapper />
</Container>
);
};

export default SponsorDetailPage;

const Container = styled.div`
display: flex;
justify-content: center;
align-items: center;
padding: 2rem 0;
width: 100%;
&:nth-child(even) {
background-color: #141414;
}
`;

const Vertical = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
margin-bottom: 2rem;
width: 100%;
`;

const H1 = styled.h1`
margin-top: 3rem;
font-size: 40px;
color: #b0a8fe;
@media only screen and (max-width: 810px) {
padding: 0 1rem;
font-size: 24px;
}
`;

const H3 = styled.h3`
margin-top: 1.5rem;
font-size: 24px;
color: #b0a8fe;
@media only screen and (max-width: 810px) {
padding: 0 1rem;
font-size: 16px;
}
`;
36 changes: 24 additions & 12 deletions src/pages/Sponsor/SponsorLevelList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ const SponsorLevelList = () => {
const [listOfSponsorLevel, setListOfSponsorLevel] = useState<SponsorLevel[][]>([]);
const [listOfSponsorBenefit, setListOfSponsorBenefit] = useState<SponsorBenefit[]>([]);

const getBenefitDescription = (benefit: SponsorBenefit | undefined) => {
if (benefit === undefined) return "-";
if (benefit.is_countable) {
return benefit.offer ? `${benefit.offer}${benefit.unit}` : benefit.uncountable_offer;
}
return benefit.uncountable_offer;
};

useEffect(() => {
SponsorAPI.listSponsorLevels().then((levels) => {
if (levels.length > 4) {
const half_length = Math.ceil(levels.length / 2);
const firstSide = levels.slice(0, half_length);
const secondSide = levels.slice(half_length);
const onlyVisible = levels.filter((level) => level.visible);
if (onlyVisible.length > 4) {
const half_length = Math.ceil(onlyVisible.length / 2);
const firstSide = onlyVisible.slice(0, half_length);
const secondSide = onlyVisible.slice(half_length);
setListOfSponsorLevel([firstSide, secondSide]);
} else {
setListOfSponsorLevel([levels]);
setListOfSponsorLevel([onlyVisible]);
}
});
SponsorAPI.listSponsorBenefits().then((benefits) => {
Expand Down Expand Up @@ -47,13 +56,11 @@ const SponsorLevelList = () => {
(benefitByLevel) => benefitByLevel.id === benefit.id
);
return (
<td>
{benefitAboutLevel?.is_countable ? `` : ``}
{benefitAboutLevel?.offer === 0
? "-"
: benefitAboutLevel?.offer.toString()}
{benefitAboutLevel?.is_countable && benefitAboutLevel?.unit}
</td>
<td
dangerouslySetInnerHTML={{
__html: getBenefitDescription(benefitAboutLevel),
}}
></td>
);
})}
</tr>
Expand Down Expand Up @@ -201,6 +208,11 @@ const SponsorRatingTable = styled.div`
font-size: 10px;
}
& > * {
color: #b0a8fe;
margin: 0;
}
border-bottom: 1px solid #b0a8fe;
padding: 1rem 0;
text-align: center;
Expand Down
36 changes: 19 additions & 17 deletions src/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import React from "react"
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom"
import React from "react";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";

import Footer from "components/Footer"
import Nav from "components/Nav"
import { DialogCollection } from "dialogs"
import Coc from "pages/About/coc"
import Pyconkr2024 from "pages/About/pyconkr2024"
import Cfp from "pages/Contribution/cfp"
import Home from "pages/Home"
import NotFound from "pages/NotFound"
import PrivacyPolicy from "pages/PrivacyPolicy"
import { SessionDetailPage } from "pages/Session/detail"
import { SessionListPage } from "pages/Session/list"
import { SessionTimeTablePage } from "pages/Session/timetable"
import SponsorPage from "pages/Sponsor"
import TermsOfService from "pages/TermsOfService"
import Health from "./pages/About/health"
import Footer from "components/Footer";
import Nav from "components/Nav";
import { DialogCollection } from "dialogs";
import Coc from "pages/About/coc";
import Pyconkr2024 from "pages/About/pyconkr2024";
import Cfp from "pages/Contribution/cfp";
import Home from "pages/Home";
import NotFound from "pages/NotFound";
import PrivacyPolicy from "pages/PrivacyPolicy";
import { SessionDetailPage } from "pages/Session/detail";
import { SessionListPage } from "pages/Session/list";
import { SessionTimeTablePage } from "pages/Session/timetable";
import SponsorPage from "pages/Sponsor";
import TermsOfService from "pages/TermsOfService";
import Health from "./pages/About/health";
import SponsorDetailPage from "pages/Sponsor/SponsorDetail";

const Router = () => {
return (
Expand All @@ -27,6 +28,7 @@ const Router = () => {
<Route path="/about/coc" element={<Coc />} />
<Route path="/about/health" element={<Health />} />
<Route path="/sponsoring/sponsor/prospectus" element={<SponsorPage />} />
<Route path="/sponsoring/sponsor/:id" element={<SponsorDetailPage />} />
<Route path="/session" element={<SessionListPage />} />
<Route path="/session/:code" element={<SessionDetailPage />} />
<Route path="/session/timetable" element={<SessionTimeTablePage />} />
Expand Down
6 changes: 6 additions & 0 deletions src/utils/hooks/useAPI.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useSuspenseQuery } from '@tanstack/react-query'

import { listSessions, retriveSession } from "api/session"
import { detailSponsor } from "api/sponsor";

const QUERY_KEYS = {
SESSION_LIST: ['session', 'list'],
Expand All @@ -15,3 +16,8 @@ export const useRetriveSessionQuery = (code: string) => useSuspenseQuery({
queryKey: ['session', 'retrive', code],
queryFn: () => retriveSession(code),
})

export const useRetrieveSponsorQuery = (id: string) => useSuspenseQuery({
queryKey: ["sponsor", "retrieve", id],
queryFn: () => detailSponsor(id),
})
Loading

0 comments on commit 20bd691

Please sign in to comment.