Skip to content

Commit

Permalink
[Feat/#41] 전체 매출액, 월별 매출액, 클래스별 연간 매출액, 지출액 수정 api 연결 (#46)
Browse files Browse the repository at this point in the history
* feat: 전체 매출액 api 연결

* feat: 월별 매출액 api 연결

* feat: 클래스별 연간 매출액 api 연결

* feat: 지출액 수정 api 연결
  • Loading branch information
seoyeon08 authored Jul 4, 2024
1 parent ae725da commit ebdaa66
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 211 deletions.
46 changes: 39 additions & 7 deletions src/apis/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ export class ApiClient
return response.data;
}

//---------revenue---------
// 예약자 정보
async peopleList(lessondateId: PeopleListReqType) {
console.log('전달된 lessondate_id: ', lessondateId);
Expand All @@ -314,12 +313,45 @@ export class ApiClient

//---------revenue---------

// 임의 데이터. 클래스 년/월 별 매출액
public static async getMonthSales(): Promise<MonthSalesType[]> {
const apiUrl = '/data/monthRevenue.json';
const response = await fetch(apiUrl);
const data = await response.json();
return data;
async getTotal() {
const response = await this.axiosInstance.request<
BaseResponseType<TotalType>
>({
method: 'get',
url: '/revenue/total',
});
return response.data;
}

async getMonthRevenue(year: number, month: number) {
const response = await this.axiosInstance.request<
BaseResponseType<MonthRevenueType[]>
>({
method: 'get',
url: `/revenue/${year}/${month}`,
});
return response.data;
}

async getLessonRevenue(year: number, lessonId: number) {
const response = await this.axiosInstance.request<
BaseResponseType<LessonRevenue[]>
>({
method: 'get',
url: `/revenue/lesson/${year}/${lessonId}`,
});
return response.data;
}

async updatePrice(reqData: PriceReqType) {
const response = await this.axiosInstance.request<
BaseResponseType<PriceType>
>({
method: 'put',
url: '/revenue/update',
data: reqData,
});
return response.data;
}

static getInstance(): ApiClient {
Expand Down
15 changes: 15 additions & 0 deletions src/apis/interfaces/revenueApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export interface revenueApi {
getTotal(): Promise<BaseResponseType<TotalType>>;

getMonthRevenue(
year: number,
month: number
): Promise<BaseResponseType<MonthRevenueType[]>>;

getLessonRevenue(
year: number,
lessonId: number
): Promise<BaseResponseType<LessonRevenue[]>>;

updatePrice(reqData: PriceReqType): Promise<BaseResponseType<PriceType>>;
}
95 changes: 67 additions & 28 deletions src/components/molecules/Calculator.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { BsPencil } from 'react-icons/bs';
import { GrFormNext, GrFormPrevious } from 'react-icons/gr';
import Keypad from '../common/Keypad';
import { EditPrice } from './EditPrice';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { ApiClient } from '../../apis/apiClient';
interface IProps {
data: any;
lessonId: number;
year: number;
}

const formatNumber = (value: number) => {
return new Intl.NumberFormat('ko-KR').format(value);
};

export const Calculator = () => {
export const Calculator = ({ data, lessonId, year }: IProps) => {
const currentMonth = new Date().getMonth() + 1;
const [month, setMonth] = useState(6);

const [month, setMonth] = useState(currentMonth);
const [editPriceVisible, setEditPriceVisible] = useState(false);
const [keypadVisible, setKeypadVisible] = useState(false);
const [valueSetter, setValueSetter] = useState<
((value: string) => void) | null
>(null);

const [totalSales, setTotalSales] = useState(762000);
const [totalPrice, setTotalPrice] = useState(250000);
const [materialPrice, setMaterialPrice] = useState(100000);
const [rentalPrice, setRentalPrice] = useState(100000);
const [etcPrice, setEtcPrice] = useState(50000);
const [totalSales, setTotalSales] = useState(0);
const [totalPrice, setTotalPrice] = useState(0);
const [materialPrice, setMaterialPrice] = useState(0);
const [rentalPrice, setRentalPrice] = useState(0);
const [etcPrice, setEtcPrice] = useState(0);
const netProfit = totalSales - totalPrice;

useEffect(() => {
const currentMonthData = data.find((d: any) => d.month === month);
if (currentMonthData) {
setTotalSales(currentMonthData.totalRevenue);
setMaterialPrice(currentMonthData.materialPrice);
setRentalPrice(currentMonthData.rentalPrice);
setEtcPrice(currentMonthData.etcPrice);
setTotalPrice(currentMonthData.totalSales);
}
}, [month, data]);

const handlePreviousMonth = () => {
setMonth((prevMonth) => (prevMonth > 1 ? prevMonth - 1 : 1));
};
Expand All @@ -37,19 +49,47 @@ export const Calculator = () => {

const openEditPrice = () => {
setEditPriceVisible(true);
setKeypadVisible(true);
};

const closeEditPrice = () => {
setEditPriceVisible(false);
setKeypadVisible(false);
};

const saveEditPrice = (material: string, rental: string, etc: string) => {
setMaterialPrice(Number(material));
setRentalPrice(Number(rental));
setEtcPrice(Number(etc));
setTotalPrice(Number(material) + Number(rental) + Number(etc));
const reqData: PriceReqType = {
lessonId: lessonId,
year: year,
month: month,
materialPrice: materialPrice,
rentalPrice: rentalPrice,
etcPrice: etcPrice,
};
const queryClient = useQueryClient();
const { mutate: updatePrice } = useMutation({
mutationFn: async () => {
const response = await ApiClient.getInstance().updatePrice(reqData);
return response;
},
onSuccess: async (response) => {
console.log('성공');
if (response.data) {
setMaterialPrice(response.data.materialPrice);
setRentalPrice(response.data.rentalPrice);
setEtcPrice(response.data.etcPrice);
setTotalPrice(
response.data.materialPrice +
response.data.rentalPrice +
response.data.etcPrice
);
queryClient.invalidateQueries({ queryKey: ['monthRevenue'] });
}
},
onError: async () => {
console.log('에러');
},
});

const saveEditPrice = () => {
updatePrice();
};

return (
Expand Down Expand Up @@ -106,15 +146,14 @@ export const Calculator = () => {
<EditPrice
closeEditPrice={closeEditPrice}
saveEditPrice={saveEditPrice}
setValue={setValueSetter}
initialMaterialPrice={materialPrice}
initialRentalPrice={rentalPrice}
initialEtcPrice={etcPrice}
setMaterialPrice={setMaterialPrice}
setRentalPrice={setRentalPrice}
setEtcPrice={setEtcPrice}
/>
)}
{/* {keypadVisible && (
<Keypad
setValue={(value) => valueSetter && valueSetter(value)}
closeKeypad={() => setKeypadVisible(false)}
/>
)} */}
</div>
);
};
74 changes: 41 additions & 33 deletions src/components/molecules/EditPrice.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,59 @@
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { CgClose } from 'react-icons/cg';

interface IProps {
closeEditPrice: () => void;
saveEditPrice: (
materialPrice: string,
rentalPrice: string,
etcPrice: string
) => void;
setValue: (setter: (value: string) => void) => void;
saveEditPrice: () => void;
initialMaterialPrice: number;
initialRentalPrice: number;
initialEtcPrice: number;
setMaterialPrice: (materialPrice: number) => void;
setRentalPrice: (rentalPrice: number) => void;
setEtcPrice: (etcPrice: number) => void;
}

const formatNumber = (value: string) => {
return value.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

const unformatNumber = (value: string) => {
return value.replace(/,/g, '');
const formatNumber = (value: number) => {
return value.toLocaleString('ko-KR');
};

export const EditPrice = ({
closeEditPrice,
saveEditPrice,
setValue,
initialMaterialPrice,
initialRentalPrice,
initialEtcPrice,
setMaterialPrice,
setRentalPrice,
setEtcPrice,
}: IProps) => {
const [materialPrice, setMaterialPrice] = useState('');
const [rentalPrice, setRentalPrice] = useState('');
const [etcPrice, setEtcPrice] = useState('');
const [materialPrice, setInputMaterialPrice] = useState<number>(0);
const [rentalPrice, setInputRentalPrice] = useState<number>(0);
const [etcPrice, setInputEtcPrice] = useState<number>(0);

useEffect(() => {
setInputMaterialPrice(initialMaterialPrice);
setInputRentalPrice(initialRentalPrice);
setInputEtcPrice(initialEtcPrice);
}, [initialMaterialPrice, initialRentalPrice, initialEtcPrice]);

const handleSave = () => {
saveEditPrice(
unformatNumber(materialPrice),
unformatNumber(rentalPrice),
unformatNumber(etcPrice)
);
setMaterialPrice(materialPrice);
setRentalPrice(rentalPrice);
setEtcPrice(etcPrice);
saveEditPrice();
closeEditPrice();
};

const unformatNumber = (value: string) => {
return value.replace(/,/g, '');
};

const handleChange =
(setter: (value: string) => void) =>
(setter: (value: number) => void) =>
(e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
if (/^\d*\.?\d*$/.test(unformatNumber(value))) {
setter(formatNumber(unformatNumber(value)));
setter(Number(unformatNumber(value)));
}
};

Expand All @@ -61,9 +72,8 @@ export const EditPrice = ({
<input
type='text'
className='border-b-[1px] border-hanaSilver w-24 text-right'
value={materialPrice}
onChange={handleChange(setMaterialPrice)}
onFocus={() => setValue(setMaterialPrice)}
value={formatNumber(materialPrice)}
onChange={handleChange(setInputMaterialPrice)}
/>{' '}
</span>
Expand All @@ -74,9 +84,8 @@ export const EditPrice = ({
<input
type='text'
className='border-b-[1px] border-hanaSilver w-24 text-right'
value={rentalPrice}
onChange={handleChange(setRentalPrice)}
onFocus={() => setValue(setRentalPrice)}
value={formatNumber(rentalPrice)}
onChange={handleChange(setInputRentalPrice)}
/>{' '}
</span>
Expand All @@ -87,9 +96,8 @@ export const EditPrice = ({
<input
type='text'
className='border-b-[1px] border-hanaSilver w-24 text-right'
value={etcPrice}
onChange={handleChange(setEtcPrice)}
onFocus={() => setValue(setEtcPrice)}
value={formatNumber(etcPrice)}
onChange={handleChange(setInputEtcPrice)}
/>{' '}
</span>
Expand Down
Loading

0 comments on commit ebdaa66

Please sign in to comment.