Skip to content

Commit

Permalink
Merge pull request #72 from BCSDLab/feat/modify_benefit
Browse files Browse the repository at this point in the history
[혜택관리] 혜택 문구 추가, 수정 기능 추가
  • Loading branch information
chaeseungyun authored Dec 17, 2024
2 parents ece7442 + 07d0a66 commit 295e9dd
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 101 deletions.
24 changes: 22 additions & 2 deletions src/model/benefit.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ export interface BenefitCategoryContent {

export interface GetBenefitShopsResponse {
count: number;
shops: Shops[];
shops: ShopInfo[];
}

export interface Shops {
id: number;
name: string;
}

export interface ShopInfo extends Shops {
shop_benefit_map_id: number;
detail: string;
}

export interface SearchResponse {
benefit_shops: Shops[];
non_benefit_shops: Shops[]
Expand All @@ -41,11 +46,26 @@ export interface DeleteShopsRequest {
id: number;
}

export interface AddShopRequest extends DeleteShopsRequest {}
export interface ShopDetail {
shop_id: number;
detail: string;
}

export interface AddShopRequest {
id: number;
shop_details: ShopDetail[];
}

export interface ModifyBenefitRequest {
body: CreateBenefitRequest;
id: number;
}

export interface ModifyBenefitDetails {
modify_details: {
shop_benefit_map_id: number;
detail: string;
}[];
}

export interface ModifyBenefitForm extends CreateBenefitRequest { }
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@ export const SearchWrapper = styled.div`
position: relative;
`;

export const SelectContainer = styled.div`
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: repeat(auto-fill, 50px);
place-items: center;
width: 100%;
height: 600px;
overflow: auto;
padding: 25px;
border: 0.5px solid #eeeeeeff;
background: #eee;
`;

export const FlexColumn = styled.div`
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -54,12 +41,12 @@ export const ButtonContent = styled.span`
`;

export const ButtonWrapper = styled.div`
display: relative;
position: relative;
`;

export const DeleteButtonWrapper = styled.button`
position: absolute;
top: -10px;
top: -15px;
left: -10px;
background: none;
border: none;
Expand All @@ -72,3 +59,10 @@ export const FlexRight = styled.div`
justify-content: flex-end;
margin-top: 10px
`;

export const DetailInput = styled.input`
width: 100%;
height: 100%;
border: none;
outline: none;
`;
70 changes: 54 additions & 16 deletions src/pages/Services/Benefit/components/AdditionalModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@ import { useAddBenefitShopsMutation, useSearchShopsQuery } from 'store/api/benef
import { Shops } from 'model/benefit.model';
import { MinusCircleOutlined, UploadOutlined } from '@ant-design/icons';
import * as S from './index.style';
// eslint-disable-next-line
import * as Style from '../../index.style';

interface Props {
id: number | undefined;
closeAdditionModal: () => void;
}

interface ShopDetail {
shop_id: number;
detail: string;
}

const { Search } = Input;
export default function AdditionalModal({ id, closeAdditionModal }: Props) {
const [keyword, setKeyword] = useState<string>('');
const [isFocus, setIsFocus] = useState(false);
const [shops, setShops] = useState<Shops[]>([]);
const [details, setDetails] = useState<ShopDetail[]>([]);
const searchRef = useRef<InputRef>(null);
const userInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setKeyword(e.target.value);
Expand All @@ -33,29 +41,48 @@ export default function AdditionalModal({ id, closeAdditionModal }: Props) {
const addShop = (shopId: number, name: string) => {
if (shops.find((shop) => shop.id === shopId)) return;
setShops((prev) => [...prev, { id: shopId, name }]);
setDetails((prev) => [...prev, { shop_id: shopId, detail: '' }]);
setKeyword('');
};
const cancelAddShop = (shopId: number) => {
const filteredShop = shops.filter((shop) => shop.id !== shopId);
const filteredDetail = details.filter((shop) => shop.shop_id !== shopId);
setShops(filteredShop);
setDetails(filteredDetail);
};

const ConfirmAddShop = async () => {
if (shops.length === 0) {
closeAdditionModal();
return;
}
if (id) {
const requestBody = shops.map((shop) => shop.id);
await addShopMutation({ id, shop_ids: requestBody })
if (details.some((shop) => shop.detail === '')) {
message.error('상세정보를 입력해주세요.');
return;
}
await addShopMutation({ id, shop_details: details })
.then(() => {
message.success('상점을 추가했습니다.');
setShops([]);
setDetails([]);
setKeyword('');
closeAdditionModal();
});
}
};

const handleDetail = (e: React.ChangeEvent<HTMLInputElement>, shopId: number) => {
const { value } = e.target;
const shopDetail = details.find((shop) => shop.shop_id === shopId);
if (shopDetail) {
const filteredDetail = details.filter((shop) => shop.shop_id !== shopId);
setDetails([...filteredDetail, { shop_id: shopId, detail: value }]);
} else {
setDetails((prev) => [...prev, { shop_id: shopId, detail: value }]);
}
};

if (isError) message.error('상점을 추가할 수 없습니다.');

return (
Expand Down Expand Up @@ -87,20 +114,31 @@ export default function AdditionalModal({ id, closeAdditionModal }: Props) {
</S.SearchWrapper>

<Divider orientation="left">선택 상점</Divider>
<S.SelectContainer>
{shops.map((shop) => (
<S.ButtonWrapper key={shop.id}>
<Button style={{ width: '180px' }}>
<S.DeleteButtonWrapper onClick={() => cancelAddShop(shop.id)}>
<MinusCircleOutlined />
</S.DeleteButtonWrapper>
<S.ButtonContent>
{shop.name}
</S.ButtonContent>
</Button>
</S.ButtonWrapper>
))}
</S.SelectContainer>
<Style.ShopList>
<thead>
<Style.HeaderRow>
<Style.HeaderItem>상점명</Style.HeaderItem>
<Style.HeaderItem>상세정보</Style.HeaderItem>
</Style.HeaderRow>
</thead>
<tbody>
{shops.map((shop) => (
<Style.Row key={shop.id} isclicked={false}>
<Style.TitleItem>
<S.ButtonWrapper key={shop.id}>
<S.DeleteButtonWrapper onClick={() => cancelAddShop(shop.id)}>
<MinusCircleOutlined />
</S.DeleteButtonWrapper>
{shop.name}
</S.ButtonWrapper>
</Style.TitleItem>
<Style.DetailItem>
<S.DetailInput onChange={(e) => handleDetail(e, shop.id)} />
</Style.DetailItem>
</Style.Row>
))}
</tbody>
</Style.ShopList>
<S.FlexRight>
<Button
onClick={ConfirmAddShop}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {
Divider, Button, message,
} from 'antd';
import { MinusCircleOutlined, UploadOutlined } from '@ant-design/icons';
import * as S from 'pages/Services/Benefit/components/AdditionalModal/index.style';
import { ShopInfo } from 'model/benefit.model';
import { useEffect, useState } from 'react';
import { useModifyBenefitDetailsMutation } from 'store/api/benefit';
import * as Style from 'pages/Services/Benefit/index.style';

interface Props {
closeBenefitModifyModal: () => void;
shops?: ShopInfo[];
}

interface ModifyDetails {
shop_id: number;
detail: string;
name: string;
shop_benefit_map_id: number;
}

export default function BenefitDetailModifyModal({ closeBenefitModifyModal, shops }: Props) {
const [details, setDetails] = useState<ModifyDetails[]>([]);
const [mutation] = useModifyBenefitDetailsMutation();

const handleDetail = (e: React.ChangeEvent<HTMLInputElement>, shopId: number) => {
const { value } = e.target;
const shopDetail = details.find((shop) => shop.shop_id === shopId);
if (shopDetail) {
const findItem = details.find((shop) => shop.shop_id === shopId);
if (!findItem) return;
const newDetail = {
shop_id: findItem.shop_id,
detail: value,
name: findItem.name,
shop_benefit_map_id: findItem.shop_benefit_map_id,
};
const filteredDetail = details.filter((shop) => shop.shop_id !== shopId);
setDetails([...filteredDetail, newDetail]);
} else {
setDetails((prev) => [...prev, {
shop_id: shopId,
detail: value,
name: shops?.find((shop) => shop.id === shopId)?.name || '',
shop_benefit_map_id: shops?.find((shop) => shop.id === shopId)?.shop_benefit_map_id || 0,
}]);
}
};

const modifyDetails = () => {
const shopDetails = details.map((shop) => ({
shop_benefit_map_id: shop.shop_benefit_map_id,
detail: shop.detail,
}));
mutation({ modify_details: shopDetails });
};

const confirmModifyDetails = () => {
if (details.some((shop) => shop.detail.trim() === '')) {
message.error('상세정보를 입력해주세요.');
return;
}
modifyDetails();
closeBenefitModifyModal();
};

useEffect(() => {
if (shops) {
const shopDetails = shops.map((shop) => ({
shop_id: shop.id,
detail: shop.detail,
name: shop.name,
shop_benefit_map_id: shop.shop_benefit_map_id,
}));
setDetails(shopDetails);
}
}, [shops]);

if (!shops) return null;

return (
<div>
<Divider orientation="left">선택 상점</Divider>
<Style.ShopList>
<thead>
<Style.HeaderRow>
<Style.HeaderItem>상점명</Style.HeaderItem>
<Style.HeaderItem>상세정보</Style.HeaderItem>
</Style.HeaderRow>
</thead>
<tbody>
{details.map((shop) => (
<Style.Row key={shop.shop_id} isclicked={false}>
<Style.TitleItem>
<S.ButtonWrapper key={shop.shop_id}>
<S.DeleteButtonWrapper>
<MinusCircleOutlined />
</S.DeleteButtonWrapper>
{shop.name}
</S.ButtonWrapper>
</Style.TitleItem>
<Style.DetailItem>
<S.DetailInput
onChange={(e) => handleDetail(e, shop.shop_id)}
value={details.find((detail) => detail.shop_id === shop.shop_id)?.detail}
/>
</Style.DetailItem>
</Style.Row>
))}
</tbody>
</Style.ShopList>
<S.FlexRight>
<Button
onClick={confirmModifyDetails}
>
<UploadOutlined />
완료
</Button>
</S.FlexRight>
</div>
);
}
Loading

0 comments on commit 295e9dd

Please sign in to comment.