Skip to content

Commit

Permalink
Merge pull request #103 from Moaguide-develop/feat/productpage
Browse files Browse the repository at this point in the history
Feat/productpage
  • Loading branch information
eun-hak authored Oct 25, 2024
2 parents bb3ad69 + a0a173c commit 4c7e0de
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 15 deletions.
6 changes: 5 additions & 1 deletion src/app/product/detail/building/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,11 @@ const BuildingDetailpage = (props: any) => {
) : sort === 'profit' ? (
<BuildingProfit url={url} />
) : sort === 'detail' ? (
<BuildingProductDetail url={url} rentType={data?.rentType} />
<BuildingProductDetail
url={url}
rentType={data?.rentType}
stayType={data?.stayType}
/>
) : undefined}
</div>
);
Expand Down
4 changes: 3 additions & 1 deletion src/components/product/TopProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ const TopProduct = memo(({ summary }: TopProductProps) => {
</div>

<div className="flex mt-[10px ] ml-[20px]">
<div className="text-gray-400">{item.price}</div>
<div className="text-gray-400">
{item.price.toLocaleString()}
</div>
<div
className={`ml-[3px] ${
item.lastDivide_rate > 0
Expand Down
46 changes: 35 additions & 11 deletions src/components/product/detail/building/BuildingProductDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,50 @@ import FloatingPopulationChart from './chart/FloatingPopulationChart';
import PopulationInformationChart from './chart/PopulationInformationChart';
import PublicTransport from './PublicTransport';
import OfficialPriceChart from './chart/OfficialPriceChart';
import AccommodationVisitorsChart from './chart/AccommodationVisitorsChart';
import AccommoationRateChart from './chart/AccommodationRateChart';
const BuildingProductDetail = ({
url,
rentType
rentType,
stayType
}: {
url: string;
rentType: boolean | undefined;
stayType: boolean | undefined;
}) => {
console.log(rentType);
console.log(stayType);
return (
<div className="max-w-[1000px] mx-auto mt-[32px]">
<div>
<span className=" text-2xl font-bold mb-[20px]"> 상권 임대료 </span>
<span className="text-lg ml-4 text-red-500"> (단위: 천원/m&sup2;)</span>
</div>
{stayType ? (
<>
<div>
<span className=" text-2xl font-bold mb-[20px]">숙박 유형별 방문자 수</span>
</div>

<CommercialRentChart rentType={rentType} />
<div>
<span className=" text-2xl font-bold mb-[20px]">상권 공실률</span>
<span className="text-lg ml-4 text-red-500"> (단위: %)</span>
</div>
<CommercialVacancyRateChart rentType={rentType} />
<AccommodationVisitorsChart />
<div>
<span className=" text-2xl font-bold mb-[20px]">
숙박 방문자 비율 / 평균 숙박일
</span>
</div>
<AccommoationRateChart />
</>
) : (
<>
{' '}
<div>
<span className=" text-2xl font-bold mb-[20px]"> 상권 임대료 </span>
<span className="text-lg ml-4 text-red-500"> (단위: 천원/m&sup2;)</span>
</div>
<CommercialRentChart rentType={rentType} />
<div>
<span className=" text-2xl font-bold mb-[20px]">상권 공실률</span>
<span className="text-lg ml-4 text-red-500"> (단위: %)</span>
</div>
<CommercialVacancyRateChart rentType={rentType} />
</>
)}

<div>
<span className=" text-2xl font-bold mb-[20px]">공시지가</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import React, { useState, useRef, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { usePathname } from 'next/navigation';
import { IStayRateData } from '@/types/BuildingProductType';
import { Chart } from 'react-chartjs-2';
import { TooltipItem } from 'chart.js';

const AccommoationRateChart = () => {
const pathname = usePathname();
const lastSegment = pathname.split('/').pop();
const [startYear, setStartYear] = useState<number>(2022);
const [endYear, setEndYear] = useState<number>(2024);
const fetchData = async () => {
try {
const response = await axios.get<IStayRateData>(
`https://api.moaguide.com/detail/building/stay/rate/${lastSegment}?syear=${startYear}&eyear=${endYear}`
);
return response.data;
} catch (error) {
console.error('Error fetching data:', error);
throw error; // 에러를 다시 던져서 useQuery의 onError로 전달
}
};

const {
data: CopyRightFeeData,
isLoading,
error
} = useQuery({
queryKey: ['AccommodationRate', startYear, lastSegment, endYear],
queryFn: fetchData
});

const AccommodationRateDay = CopyRightFeeData?.object.map((item) => item.day);

const AccommodationRatevalue = CopyRightFeeData?.object.map((item) => item.value);

const AccommodationRateRate = CopyRightFeeData?.object.map((item) => item.rate);

const data = {
labels: AccommodationRateDay,
datasets: [
{
type: 'bar' as const,
label: '평균 숙박 일수',
data: AccommodationRatevalue,
backgroundColor: (context: any) => {
const chart = context.chart;
const { ctx, chartArea } = chart;

if (!chartArea) {
return null;
}

const gradient = ctx.createLinearGradient(
0,
chartArea.bottom,
0,
chartArea.top
);
gradient.addColorStop(0, 'rgba(140, 192, 250, 0.8)');
gradient.addColorStop(1, '#2575d1');

return gradient;
},
yAxisID: 'y1',
borderRadius: 5,
barThickness: 20,
barPercentage: 0.2,
categoryPercentage: 0.5,

datalabels: {
display: false,
align: 'end' as const,
anchor: 'end' as const,
color: '#000',
formatter: (value: number) => `${value}`
}
},
{
type: 'line' as const,
label: '숙박 방문자 비율',
data: AccommodationRateRate,
borderColor: '#0000FF',
backgroundColor: '#0000FF',
pointBackgroundColor: '#0000FF',
pointBorderColor: '#0000FF',
fill: false,
tension: 0.4,
yAxisID: 'y2',
pointStyle: 'circle',
pointRadius: 6,
datalabels: {
display: false
}
}
]
};

const options = {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
scales: {
x: {
display: true,
grid: {
display: false
}
},
y1: {
type: 'linear' as const,
position: 'left' as const,
grid: {
display: false
},
beginAtZero: true,
// max: BarnewVariable,
ticks: {
stepSize: 10
}
},
y2: {
type: 'linear' as const,
position: 'right' as const,
grid: {
display: false
},
// max: LinenewVariable,
beginAtZero: true
}
},
plugins: {
legend: {
display: false,
position: 'top' as const
},
tooltip: {
enabled: true,
intersect: false,
callbacks: {
label: function (context: TooltipItem<'bar' | 'line'>) {
const label = context.dataset.label || '';
const value = context.raw as number;
const unit = context.dataset.type === 'bar' ? '일' : '%';
// return `${label}: ${value.toLocaleString()}${unit}`;
return ``;
},
beforeBody: function (context: TooltipItem<'bar' | 'line'>[]) {
const index = context[0].dataIndex;
const datasets = context[0].chart.data.datasets;

let tooltipText = '';
datasets.forEach((dataset) => {
const value = dataset.data[index] as number;
const unit = dataset.type === 'bar' ? '일' : '%';
tooltipText += `${dataset.label}: ${value.toLocaleString()}${unit}\n`;
});

return tooltipText;
}
}
},
datalabels: {
display: true
}
}
};

return (
<div>
<div className="flex justify-end mb-4">
<div>
<select
id="startYear"
value={startYear}
onChange={(e) => setStartYear(parseInt(e.target.value))}
className="border rounded p-1">
{[2022, 2023, 2024].map((year) => (
<option key={year} value={year}>
{year}
</option>
))}
</select>
~
<select
id="endYear"
value={endYear}
onChange={(e) => setEndYear(parseInt(e.target.value))}
className="border rounded p-1">
{[2022, 2023, 2024].map((year) => (
<option key={year} value={year}>
{year}
</option>
))}
</select>
</div>
</div>

<div className="flex flex-col items-center justify-center h-full bg-gray-50 mb-[100px]">
<div className="w-full max-w-5xl h-[500px]">
<Chart type="bar" data={data} options={options} />
</div>
</div>
</div>
);
};

export default AccommoationRateChart;
Loading

0 comments on commit 4c7e0de

Please sign in to comment.