From 1b1a8b92270598b85af8bcdf63902a2e390dd9c8 Mon Sep 17 00:00:00 2001 From: withsang Date: Thu, 30 Nov 2023 02:17:18 +0900 Subject: [PATCH] feat(text): add party text --- .../LocalCouncilReportText/PartyText.tsx | 71 ++++++++++-------- .../MetroCouncilReportText/PartyText.tsx | 75 +++++++++++-------- .../organisms/LocalCouncilReport.tsx | 33 +++++--- .../organisms/MetroCouncilReport.tsx | 32 ++++---- src/utils/constants.ts | 14 +++- 5 files changed, 138 insertions(+), 87 deletions(-) diff --git a/src/components/molecules/LocalCouncilReportText/PartyText.tsx b/src/components/molecules/LocalCouncilReportText/PartyText.tsx index 5f6f2a5..ce352d9 100644 --- a/src/components/molecules/LocalCouncilReportText/PartyText.tsx +++ b/src/components/molecules/LocalCouncilReportText/PartyText.tsx @@ -6,28 +6,32 @@ const { Paragraph, Text } = Typography; export type PartyTextVariation = 1 | 2; export interface PartyTextData { - /** 현재 연도 */ - nowYear: ElectionYears; + /** 광역시도 id */ + metroId: number; /** 지역의회 id */ localId: number; + /** 다양성 지표 */ + partyDiversityIndex: number; /** 정당별 당선자 수 (이전 선거) */ - prevElectedPartyList: { + prevElected: { party: string; count: number; }[]; /** 정당별 후보자 수 (현 선거) */ - nowCandidatePartyList: { + currentCandidate: { party: string; count: number; }[]; /** 정당별 당선자 수 (현 선거) */ - nowElectedPartyList: { + currentElected: { party: string; count: number; }[]; } interface Props { + /** 보고서 연도입니다. */ + sgYear: ElectionYears; /** text variation을 선택할 수 있습니다(기본값: 1). */ variation?: PartyTextVariation; /** text에 들어갈 데이터입니다. */ @@ -37,18 +41,19 @@ interface Props { } const defaultData: PartyTextData = { - nowYear: 2022, + metroId: 1, localId: 1, - prevElectedPartyList: [ + partyDiversityIndex: 0.5, + prevElected: [ { party: "국민의힘", count: 5 }, { party: "더불어민주당", count: 5 }, ], - nowCandidatePartyList: [ + currentCandidate: [ { party: "국민의힘", count: 10 }, { party: "더불어민주당", count: 8 }, { party: "정의당", count: 2 }, ], - nowElectedPartyList: [ + currentElected: [ { party: "국민의힘", count: 5 }, // { party: "더불어민주당", count: 4 }, // { party: "정의당", count: 1 }, @@ -56,44 +61,50 @@ const defaultData: PartyTextData = { }; export const PartyText = ({ + sgYear, variation = 1, data = defaultData, getNameFromId, }: Props) => { if (!data) return 데이터를 불러오는 중입니다..; - const { - nowYear, - localId, - prevElectedPartyList, - nowCandidatePartyList, - nowElectedPartyList, - } = data; + const { localId, prevElected, currentCandidate, currentElected } = data; + /** 소수정당 수(거대양당을 제외한 당선자의 정당 개수)가 이전 선거보다 늘었는지 여부입니다. + * 2010년 선거는 이전 선거의 공개된 데이터가 없으므로 0과 비교합니다. + */ const minorPartyIncreased = - nowElectedPartyList.length > prevElectedPartyList.length; - const minorPartyList = nowElectedPartyList.filter( + currentElected.filter( + ({ party }) => bigParties[sgYear].indexOf(party) === -1, + ).length > + (sgYear !== 2010 + ? prevElected.filter( + ({ party }) => + bigParties[(sgYear - 4) as ElectionYears].indexOf(party) === -1, + ).length + : 0); + const minorPartyList = currentElected.filter( partyItem => - bigParties[nowYear].indexOf(partyItem.party) === -1 && + bigParties[sgYear].indexOf(partyItem.party) === -1 && partyItem.party !== "무소속", ); - const anonymousCount = nowElectedPartyList.filter( + const anonymousCount = currentElected.filter( partyItem => partyItem.party === "무소속", ).length; if (variation === 1) return ( - {nowYear}년 지방선거에서는{" "} - {nowCandidatePartyList.length}개 정당에서 후보자가,{" "} - {nowElectedPartyList.length}개 정당에서 당선자가{" "} + {sgYear}년 지방선거에서는{" "} + {currentCandidate.length}개 정당에서 후보자가,{" "} + {currentElected.length}개 정당에서 당선자가{" "} 나왔어요.

{minorPartyIncreased ? ( // 소수정당 당성자 수가 늘었다면 아래 텍스트 표시 - 지난 선거에서는 {prevElectedPartyList.length}개{" "} + 지난 선거에서는 {prevElected.length}개{" "} 정당에서만 당선자가 나왔던 걸 생각하면, 이번엔 진짜 다양한 목소리가{" "} 들린다는 거죠! 여러분의{" "} {getNameFromId(localId)?.join(" ")}에서 다양성의{" "} @@ -103,16 +114,16 @@ export const PartyText = ({ // 소수정당 당성자 수가 줄었다면 아래 텍스트 표시 이번 선거는 군소정당과 무소속 후보에게 어려웠어요.. 두 거대 양당에서{" "} - 더 많은 당선자가! {bigParties[nowYear][0]}에서{" "} + 더 많은 당선자가! {bigParties[sgYear][0]}에서{" "} - {nowElectedPartyList.filter( - partyItem => partyItem.party === bigParties[nowYear][0], + {currentElected.filter( + partyItem => partyItem.party === bigParties[sgYear][0], )[0]?.count || 0} - 명의 당선자가, {bigParties[nowYear][1]}에서{" "} + 명의 당선자가, {bigParties[sgYear][1]}에서{" "} - {nowElectedPartyList.filter( - partyItem => partyItem.party === bigParties[nowYear][1], + {currentElected.filter( + partyItem => partyItem.party === bigParties[sgYear][1], )[0]?.count || 0} 명의 당선자가 나왔어요. 지난 선거에 비하면 소수정당의 목소리가 좀{" "} diff --git a/src/components/molecules/MetroCouncilReportText/PartyText.tsx b/src/components/molecules/MetroCouncilReportText/PartyText.tsx index 6949494..bddf758 100644 --- a/src/components/molecules/MetroCouncilReportText/PartyText.tsx +++ b/src/components/molecules/MetroCouncilReportText/PartyText.tsx @@ -6,26 +6,30 @@ const { Paragraph, Text } = Typography; export type PartyTextVariation = 1 | 2; export interface PartyTextData { - /** 현재 연도 */ - nowYear: ElectionYears; + /** 광역시도 id */ + metroId: number; + /** 다양성 지표 */ + partyDiversityIndex: number; /** 정당별 당선자 수 (이전 선거) */ - prevElectedPartyList: { + prevElected: { party: string; count: number; }[]; /** 정당별 후보자 수 (현 선거) */ - nowCandidatePartyList: { + currentCandidate: { party: string; count: number; }[]; /** 정당별 당선자 수 (현 선거) */ - nowElectedPartyList: { + currentElected: { party: string; count: number; }[]; } interface Props { + /** 보고서 연도입니다. */ + sgYear: ElectionYears; /** text variation을 선택할 수 있습니다(기본값: 1). */ variation?: PartyTextVariation; /** text에 들어갈 데이터입니다. */ @@ -33,55 +37,66 @@ interface Props { } const defaultData: PartyTextData = { - nowYear: 2022, - prevElectedPartyList: [ + metroId: 1, + partyDiversityIndex: 0.5, + prevElected: [ { party: "국민의힘", count: 5 }, { party: "더불어민주당", count: 5 }, ], - nowCandidatePartyList: [ + currentCandidate: [ { party: "국민의힘", count: 10 }, { party: "더불어민주당", count: 8 }, { party: "정의당", count: 2 }, ], - nowElectedPartyList: [ + currentElected: [ { party: "국민의힘", count: 5 }, { party: "더불어민주당", count: 4 }, { party: "정의당", count: 1 }, ], }; -export const PartyText = ({ variation = 1, data = defaultData }: Props) => { +export const PartyText = ({ + sgYear, + variation = 1, + data = defaultData, +}: Props) => { if (!data) return 데이터를 불러오는 중입니다..; - const { - nowYear, - prevElectedPartyList, - nowCandidatePartyList, - nowElectedPartyList, - } = data; + const { prevElected, currentCandidate, currentElected } = data; + /** 소수정당 수(거대양당을 제외한 당선자의 정당 개수)가 이전 선거보다 늘었는지 여부입니다. + * 2010년 선거는 이전 선거의 공개된 데이터가 없으므로 0과 비교합니다. + */ const minorPartyIncreased = - nowElectedPartyList.length > prevElectedPartyList.length; - const minorPartyList = nowElectedPartyList.filter( - partyItem => bigParties[nowYear].indexOf(partyItem.party) === -1, + currentElected.filter( + ({ party }) => bigParties[sgYear].indexOf(party) === -1, + ).length > + (sgYear !== 2010 + ? prevElected.filter( + ({ party }) => + bigParties[(sgYear - 4) as ElectionYears].indexOf(party) === -1, + ).length + : 0); + const minorPartyList = currentElected.filter( + partyItem => bigParties[sgYear].indexOf(partyItem.party) === -1, ); - const anonymousCount = nowElectedPartyList.filter( + const anonymousCount = currentElected.filter( partyItem => partyItem.party === "무소속", ).length; if (variation === 1) return ( - {nowYear}년 지방선거에서는{" "} - {nowCandidatePartyList.length}개 정당에서 후보자가,{" "} - {nowElectedPartyList.length}개 정당에서 당선자가{" "} + {sgYear}년 지방선거에서는{" "} + {currentCandidate.length}개 정당에서 후보자가,{" "} + {currentElected.length}개 정당에서 당선자가{" "} 나왔어요.

{minorPartyIncreased ? ( // 소수정당 당성자 수가 늘었다면 아래 텍스트 표시 - 지난 선거에서는 {prevElectedPartyList.length}개{" "} + 지난 선거에서는 {prevElected.length}개{" "} 정당에서만 당선자가 나왔던 걸 생각하면, 이번엔 진짜 다양한 목소리가{" "} 들린다는 거죠! 여러분의 광역의회에서 다양성의 바람이 솔솔~ 역대급 변화가 느껴지지 않나요? @@ -90,16 +105,16 @@ export const PartyText = ({ variation = 1, data = defaultData }: Props) => { // 소수정당 당성자 수가 줄었다면 아래 텍스트 표시 이번 선거는 군소정당과 무소속 후보에게 어려웠어요.. 두 거대 양당에서{" "} - 더 많은 당선자가! {bigParties[nowYear][0]}에서{" "} + 더 많은 당선자가! {bigParties[sgYear][0]}에서{" "} - {nowElectedPartyList.filter( - partyItem => partyItem.party === bigParties[nowYear][0], + {currentElected.filter( + partyItem => partyItem.party === bigParties[sgYear][0], )[0]?.count || 0} - 명의 당선자가, {bigParties[nowYear][1]}에서{" "} + 명의 당선자가, {bigParties[sgYear][1]}에서{" "} - {nowElectedPartyList.filter( - partyItem => partyItem.party === bigParties[nowYear][1], + {currentElected.filter( + partyItem => partyItem.party === bigParties[sgYear][1], )[0]?.count || 0} {" "} 명의 당선자가 나왔어요. 지난 선거에 비하면 소수정당의 목소리가 좀{" "} diff --git a/src/components/organisms/LocalCouncilReport.tsx b/src/components/organisms/LocalCouncilReport.tsx index 53634ec..8fcb3e5 100644 --- a/src/components/organisms/LocalCouncilReport.tsx +++ b/src/components/organisms/LocalCouncilReport.tsx @@ -10,7 +10,7 @@ import { PartyText, type AgeTextData, type GenderTextData, - // type PartyTextData, + type PartyTextData, } from "@/components/molecules/LocalCouncilReportText"; import { Histogram, @@ -19,7 +19,12 @@ import { } from "@/components/organisms/Histogram"; import { PieChart, type PieChartData } from "@/components/organisms/PieChart"; -import { axios, useGetNameFromId, useLocalElectionYears } from "@/utils"; +import { + axios, + useGetNameFromId, + useLocalElectionYears, + type ElectionYears, +} from "@/utils"; const { Title } = Typography; @@ -82,7 +87,7 @@ const LocalCouncilReport = ({ const [partyPieChartData, setPartyPieChartData] = useState(); const [partyPieChartColorMap, setPartyPieChartColorMap] = useState>(); - // const [partyTextData, setPartyTextData] = useState(); + const [partyTextData, setPartyTextData] = useState(); const getNameFromId = useGetNameFromId(idMap); @@ -104,14 +109,14 @@ const LocalCouncilReport = ({ .catch(() => { throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); }); - // axios - // .get(`localCouncil/template-data/${metroId}/${localId}?factor=party`) - // .then(response => { - // setPartyTextData(response.data as PartyTextData); - // }) - // .catch(() => { - // throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); - // }); + axios + .get(`localCouncil/template-data/${metroId}/${localId}?factor=party`) + .then(response => { + setPartyTextData(response.data as PartyTextData); + }) + .catch(() => { + throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); + }); }; // 백엔드로부터 그래프 색상들을 가져옵니다. @@ -282,7 +287,11 @@ const LocalCouncilReport = ({ {partyPieChartData && partyPieChartColorMap ? ( ) : null} - + ); }; diff --git a/src/components/organisms/MetroCouncilReport.tsx b/src/components/organisms/MetroCouncilReport.tsx index aa9a793..6fb17c4 100644 --- a/src/components/organisms/MetroCouncilReport.tsx +++ b/src/components/organisms/MetroCouncilReport.tsx @@ -10,7 +10,7 @@ import { PartyText, type AgeTextData, type GenderTextData, - // type PartyTextData, + type PartyTextData, } from "@/components/molecules/MetroCouncilReportText"; import { Histogram, @@ -19,7 +19,12 @@ import { } from "@/components/organisms/Histogram"; import { PieChart, type PieChartData } from "@/components/organisms/PieChart"; -import { axios, useGetNameFromId, useLocalElectionYears } from "@/utils"; +import { + axios, + useGetNameFromId, + useLocalElectionYears, + type ElectionYears, +} from "@/utils"; const { Title } = Typography; @@ -79,7 +84,7 @@ const MetroCouncilReport = ({ const [partyPieChartData, setPartyPieChartData] = useState(); const [partyPieChartColorMap, setPartyPieChartColorMap] = useState>(); - // const [partyTextData, setPartyTextData] = useState(); + const [partyTextData, setPartyTextData] = useState(); const getNameFromId = useGetNameFromId(idMap); @@ -101,14 +106,14 @@ const MetroCouncilReport = ({ .catch(() => { throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); }); - // axios - // .get(`metroCouncil/template-data/${metroId}?factor=party`) - // .then(response => { - // setPartyTextData(response.data as PartyTextData); - // }) - // .catch(() => { - // throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); - // }); + axios + .get(`metroCouncil/template-data/${metroId}?factor=party`) + .then(response => { + setPartyTextData(response.data as PartyTextData); + }) + .catch(() => { + throw new Error("네트워크 문제가 발생했습니다. 다시 시도해주세요."); + }); }; // 백엔드로부터 그래프 색상들을 가져옵니다. @@ -169,7 +174,6 @@ const MetroCouncilReport = ({ binMax: maxAge, count, colorGroup: colorGroupMap.get(ageGroup as ColorGroup) || 0, - // colorGroup: ageGroup as ColorGroup, }); }); setAgeHistogramData(newAgeHistogramData); @@ -277,7 +281,9 @@ const MetroCouncilReport = ({ {partyPieChartData && partyPieChartColorMap ? ( ) : null} - + {partyTextData ? ( + + ) : null} ); }; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index f5e6f17..b3bc89e 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,6 +1,16 @@ -/** 연도별 선거 당시 '거대 양당'의 목록 */ -export type ElectionYears = 2018 | 2022; +/** 지방의회 선거 + * TODO: 2010 + 4n (n >= 0)으로 확장 + */ +export type ElectionYears = 2010 | 2014 | 2018 | 2022; + +/** 연도별 선거 당시 '거대 양당'의 목록 + * TODO: API에서 받아오도록 수정 + */ export const bigParties = { + /** fixme: 2010 */ + 2010: ["민주통합당", "새누리당"], + /** fixme: 2014 */ + 2014: ["새누리당", "민주통합당"], 2018: ["더불어민주당", "자유한국당"], 2022: ["국민의힘", "더불어민주당"], };