Skip to content

Commit

Permalink
Merge pull request #747 from NUTFes/feat/kubosaka/743-update-sponsor-…
Browse files Browse the repository at this point in the history
…select

協賛活動の企業のドロップダウンに企業の検索機能を追加した
  • Loading branch information
Kubosaka authored May 20, 2024
2 parents 921a509 + 900f05b commit abafb21
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,23 @@ interface MultiSelectProps {
options: Option[];
values?: Option[];
onChange: (value: Option[]) => void;
placeholder?: string;
}

const MultiSelect: React.FC<MultiSelectProps> = ({ options, onChange, values = [options[0]] }) => {
const MultiSelect: React.FC<MultiSelectProps> = ({
options,
onChange,
values = [options[0]],
placeholder,
}) => {
const [selected, setSelected] = useState<{ value: string; label: string }[]>(values);

return (
<Select
isMulti
options={options}
value={selected}
placeholder={placeholder}
onChange={(_, actionMeta) => {
switch (actionMeta.action) {
case 'select-option':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Dispatch, useEffect, useState, SetStateAction } from 'react';
import Select from 'react-select';

interface Option {
value: string;
label: string;
}

interface SearchSelectProps {
options?: Option[];
value?: Option;
onChange?: (value: Option) => void;
setID?: Dispatch<SetStateAction<string>>;
noOptionMessage?: string;
placeholder?: string;
}

const SearchSelect: React.FC<SearchSelectProps> = ({
options,
value,
onChange,
setID,
noOptionMessage,
placeholder,
}) => {
const [selected, setSelected] = useState<Option | null>(value || (options && options[0]) || null);

useEffect(() => {
setSelected(value || (options && options[0]) || null);
}, [options]);

return (
<Select
options={options}
value={selected}
noOptionsMessage={() => noOptionMessage}
placeholder={placeholder}
onChange={(option, actionMeta) => {
switch (actionMeta.action) {
case 'select-option':
if (option) {
setSelected(option);
setID && setID(option?.value || '0');
}
break;
case 'remove-value':
case 'pop-value':
if (actionMeta.removedValue) {
setSelected(null);
setID && setID('');
}
break;
case 'clear':
setSelected(null);
setID && setID('');
break;
default:
break;
}
}}
/>
);
};

export default SearchSelect;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './SearchSelect';
1 change: 1 addition & 0 deletions view/next-project/src/components/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export { default as BureauLabel } from './BureauLabel';
export { default as Header } from './Header';
export { default as SideNav } from './SideNav';
export { default as MultiSelect } from './MultiSelect/MultiSelect';
export { default as SearchSelect } from './SearchSelect';
42 changes: 32 additions & 10 deletions view/next-project/src/components/sponsoractivities/EditModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Input,
Textarea,
} from '@components/common';
import { MultiSelect } from '@components/common';
import { MultiSelect, SearchSelect } from '@components/common';
import { BUREAUS } from '@constants/bureaus';
import { DESIGNER_VALUES } from '@constants/designers';
import {
Expand Down Expand Up @@ -46,6 +46,7 @@ export default function EditModal(props: ModalProps) {

// 協賛企業のリスト
const [formData, setFormData] = useState<SponsorActivity>(props.sponsorActivity);
const [formDataSponsorID, setFormDataSponsorID] = useState<string>(String(formData.sponsorID));
const [selectedYear, setSelectedYear] = useState<string>(props.year);
const [sponsors, setSponsors] = useState<Sponsor[]>(props.sponsors || []);

Expand Down Expand Up @@ -194,6 +195,22 @@ export default function EditModal(props: ModalProps) {
return res;
}, [bureauId]);

const sponsorOptions = useMemo(() => {
const options = sponsors
? sponsors.map((sponsor) => {
return { value: String(sponsor?.id) || '', label: sponsor.name };
})
: null;

return options;
}, [sponsors]);

useEffect(() => {
setFormData({ ...formData, sponsorID: Number(formDataSponsorID) });
}, [formDataSponsorID]);

const NO_SPONSORS_MESSAGE = '企業が登録されていません';

// 協賛企業の情報
const content = (data: SponsorActivity) => (
<div className='my-4 grid grid-cols-5 items-center justify-items-center gap-2'>
Expand All @@ -215,20 +232,25 @@ export default function EditModal(props: ModalProps) {
</div>
<p className='text-black-600'>企業名</p>
<div className='col-span-4 w-full'>
<Select className='w-full' onChange={handler('sponsorID')} value={data.sponsorID}>
{sponsors &&
sponsors.map((sponsor) => (
<option key={sponsor.id} value={sponsor.id}>
{sponsor.name}
</option>
))}
{!sponsors && <option>企業が登録されていません</option>}
</Select>
<SearchSelect
options={sponsorOptions || undefined}
setID={setFormDataSponsorID}
noOptionMessage={NO_SPONSORS_MESSAGE}
placeholder={NO_SPONSORS_MESSAGE}
value={
(sponsorOptions &&
sponsorOptions.filter((option) => {
return option.value === formDataSponsorID;
})[0]) ||
undefined
}
/>
</div>
<p className='text-black-600'>協賛スタイル</p>
<div className='col-span-4 w-full'>
<MultiSelect
options={styleOotions}
placeholder={'協賛スタイルが登録されていません'}
values={
selectedStyleIds
? styleOotions.filter((option) => selectedStyleIds.includes(Number(option.value)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useRouter } from 'next/router';
import React, { useState, useEffect, useMemo } from 'react';
import { RiArrowDropRightLine } from 'react-icons/ri';
import { get, post } from '@/utils/api/api_methods';
import { MultiSelect } from '@components/common';
import { MultiSelect, SearchSelect } from '@components/common';

import {
CloseButton,
Expand Down Expand Up @@ -54,6 +54,7 @@ export default function SponsorActivitiesAddModal(props: Props) {
expense: 0,
remark: '',
});
const [formDataSponsorID, setFormDataSponsorID] = useState<string>(String(formData.sponsorID));

const setDesign = (e: React.ChangeEvent<HTMLInputElement>) => {
const remarkOption = formData.feature === 'クーポン' ? REMARK_COUPON : '';
Expand Down Expand Up @@ -138,6 +139,7 @@ export default function SponsorActivitiesAddModal(props: Props) {
});
};

//react-selectのmulti-select用のオプション作成
const styleOotions = useMemo(() => {
const options = sponsorStyles.map((style) => {
return {
Expand Down Expand Up @@ -177,10 +179,26 @@ export default function SponsorActivitiesAddModal(props: Props) {
setSponsors(getSponsorsByYears);
};

const sponsorOptions = useMemo(() => {
const options = sponsors
? sponsors.map((sponsor) => {
return { value: String(sponsor?.id) || '', label: sponsor.name };
})
: null;

return options;
}, [sponsors]);

useEffect(() => {
getSponsors();
}, [selectedYear]);

useEffect(() => {
setFormData({ ...formData, sponsorID: Number(formDataSponsorID) });
}, [formDataSponsorID]);

const NO_SPONSORS_MESSAGE = '企業が登録されていません';

// 協賛活動の情報
const content = (data: SponsorActivity) => (
<div className='mx-auto my-10 grid grid-cols-5 items-center justify-items-center gap-2'>
Expand All @@ -202,20 +220,18 @@ export default function SponsorActivitiesAddModal(props: Props) {
</div>
<p className='text-black-600'>協賛企業</p>{' '}
<div className='col-span-4 w-full'>
<Select value={data.sponsorID} onChange={formDataHandler('sponsorID')}>
{sponsors &&
sponsors.map((sponsor: Sponsor) => (
<option key={sponsor.id} value={sponsor.id}>
{sponsor.name}
</option>
))}
{!sponsors && <option>企業が登録されていません</option>}
</Select>
<SearchSelect
options={sponsorOptions || undefined}
setID={setFormDataSponsorID}
noOptionMessage={NO_SPONSORS_MESSAGE}
placeholder={NO_SPONSORS_MESSAGE}
/>
</div>
<p className='text-black-600'>協賛スタイル</p>
<div className='col-span-4 w-full'>
<MultiSelect
options={styleOotions}
placeholder={'協賛スタイルが登録されていません'}
onChange={(value) => {
setSelectedStyleIds(value.map((v) => Number(v.value)));
}}
Expand Down
36 changes: 18 additions & 18 deletions view/next-project/src/pages/sponsoractivities/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,26 +300,26 @@ export default function SponsorActivities(props: Props) {
CSVダウンロード
</PrimaryButton>
</div>
<div className='hidden justify-end md:flex '>
<OpenModalButton
users={props.users}
sponsors={sponsors}
sponsorStyles={props.sponsorStyles}
yearPeriods={yearPeriods}
>
協賛活動登録
</OpenModalButton>
</div>
<div className='md:hidden'>
<OpenModalButton
users={props.users}
sponsors={props.sponsors}
sponsorStyles={props.sponsorStyles}
yearPeriods={yearPeriods}
/>
</div>
</div>
</div>
<div className='hidden justify-end md:flex'>
<OpenModalButton
users={props.users}
sponsors={sponsors}
sponsorStyles={props.sponsorStyles}
yearPeriods={yearPeriods}
>
協賛活動登録
</OpenModalButton>
</div>
<div className='md:hidden'>
<OpenModalButton
users={props.users}
sponsors={props.sponsors}
sponsorStyles={props.sponsorStyles}
yearPeriods={yearPeriods}
/>
</div>
<div className='mb-7 md:hidden'>
{sortedAndFilteredSponsorActivitiesViews &&
sortedAndFilteredSponsorActivitiesViews.map((sponsorActivitiesItem) => (
Expand Down

0 comments on commit abafb21

Please sign in to comment.