#58 - Autocomplete friend gift (#111)

This commit is contained in:
object 2023-01-14 06:48:51 +01:00 committed by GitHub
parent 9381b37e8a
commit b01a1dec81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 13 deletions

View File

@ -127,4 +127,32 @@
height: 60px; height: 60px;
} }
.autocomplete-gift-container {
background: #fff;
padding: 8px;
list-style-type: none;
min-width: 307px;
border-radius: 0.2rem;
position: absolute;
font-size: 0.7875rem;
top: 81px;
left: 8px;
border: 1px solid #b6c1ce;
margin: 0;
border-radius: 2px;
margin: 0;
box-sizing: border-box;
max-height: 280px;
overflow-y: auto;
z-index: 1;
.autocomplete-gift-item {
width: 100%;
box-sizing: border-box;
&:hover {
background-color: #ebf4ff;
}
}
}
@import './views/targeted-offer/Offer.scss'; @import './views/targeted-offer/Offer.scss';

View File

@ -1,10 +1,10 @@
import { GiftReceiverNotFoundEvent, PurchaseFromCatalogAsGiftComposer } from '@nitrots/nitro-renderer'; import { GiftReceiverNotFoundEvent, PurchaseFromCatalogAsGiftComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { ChangeEvent, FC, useCallback, useEffect, useMemo, useState } from 'react';
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa'; import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
import { ColorUtils, GetSessionDataManager, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../api'; import { ColorUtils, GetSessionDataManager, LocalizeText, MessengerFriend, ProductTypeEnum, SendMessageComposer } from '../../../../api';
import { Base, Button, ButtonGroup, classNames, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Base, Button, ButtonGroup, classNames, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events'; import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events';
import { useCatalog, useMessageEvent, useUiEvent } from '../../../../hooks'; import { useCatalog, useFriends, useMessageEvent, useUiEvent } from '../../../../hooks';
export const CatalogGiftView: FC<{}> = props => export const CatalogGiftView: FC<{}> = props =>
{ {
@ -23,8 +23,11 @@ export const CatalogGiftView: FC<{}> = props =>
const [ maxRibbonIndex, setMaxRibbonIndex ] = useState<number>(0); const [ maxRibbonIndex, setMaxRibbonIndex ] = useState<number>(0);
const [ receiverNotFound, setReceiverNotFound ] = useState<boolean>(false); const [ receiverNotFound, setReceiverNotFound ] = useState<boolean>(false);
const { catalogOptions = null } = useCatalog(); const { catalogOptions = null } = useCatalog();
const { friends } = useFriends();
const { giftConfiguration = null } = catalogOptions; const { giftConfiguration = null } = catalogOptions;
const [ boxTypes, setBoxTypes ] = useState<number[]>([]); const [ boxTypes, setBoxTypes ] = useState<number[]>([]);
const [ suggestions, setSuggestions ] = useState([]);
const [ isAutocompleteVisible, setIsAutocompleteVisible ] = useState(true);
const onClose = useCallback(() => const onClose = useCallback(() =>
{ {
@ -37,6 +40,8 @@ export const CatalogGiftView: FC<{}> = props =>
setMessage(''); setMessage('');
setSelectedBoxIndex(0); setSelectedBoxIndex(0);
setSelectedRibbonIndex(0); setSelectedRibbonIndex(0);
setIsAutocompleteVisible(false);
setSuggestions([]);
if(colors.length) setSelectedColorId(colors[0].id); if(colors.length) setSelectedColorId(colors[0].id);
}, [ colors ]); }, [ colors ]);
@ -56,19 +61,42 @@ export const CatalogGiftView: FC<{}> = props =>
const isColorable = useMemo(() => const isColorable = useMemo(() =>
{ {
if (!giftConfiguration) return false; if (!giftConfiguration) return false;
if (isBoxDefault) return false; if (isBoxDefault) return false;
const boxType = boxTypes[selectedBoxIndex]; const boxType = boxTypes[selectedBoxIndex];
return (boxType === 8 || (boxType >= 3 && boxType <= 6)) ? false : true; return (boxType === 8 || (boxType >= 3 && boxType <= 6)) ? false : true;
}, [ giftConfiguration, selectedBoxIndex, isBoxDefault, boxTypes ]); }, [ giftConfiguration, selectedBoxIndex, isBoxDefault, boxTypes ]);
const colourId = useMemo(() => const colourId = useMemo(() =>
{ {
return isBoxDefault ? boxTypes[selectedBoxIndex] : selectedColorId; return isBoxDefault ? boxTypes[selectedBoxIndex] : selectedColorId;
},[ isBoxDefault, boxTypes, selectedBoxIndex, selectedColorId ]) },[ isBoxDefault, boxTypes, selectedBoxIndex, selectedColorId ])
const allFriends = friends.filter( (friend: MessengerFriend) => friend.id !== -1 );
const onTextChanged = (e: ChangeEvent<HTMLInputElement>) =>
{
const value = e.target.value;
let suggestions = [];
if (value.length > 0)
{
suggestions = allFriends.sort().filter((friend: MessengerFriend) => friend.name.includes(value));
}
setReceiverName(value);
setIsAutocompleteVisible(true);
setSuggestions(suggestions);
};
const selectedReceiverName = (friendName: string) =>
{
setReceiverName(friendName);
setIsAutocompleteVisible(false);
}
const handleAction = useCallback((action: string) => const handleAction = useCallback((action: string) =>
{ {
@ -113,7 +141,7 @@ export const CatalogGiftView: FC<{}> = props =>
const castedEvent = (event as CatalogInitGiftEvent); const castedEvent = (event as CatalogInitGiftEvent);
onClose(); onClose();
setPageId(castedEvent.pageId); setPageId(castedEvent.pageId);
setOfferId(castedEvent.offerId); setOfferId(castedEvent.offerId);
setExtraData(castedEvent.extraData); setExtraData(castedEvent.extraData);
@ -126,20 +154,20 @@ export const CatalogGiftView: FC<{}> = props =>
{ {
setReceiverNotFound(false); setReceiverNotFound(false);
}, [ receiverName ]); }, [ receiverName ]);
const createBoxTypes = useCallback(() => const createBoxTypes = useCallback(() =>
{ {
if (!giftConfiguration) return; if (!giftConfiguration) return;
setBoxTypes(prev => setBoxTypes(prev =>
{ {
let newPrev = [ ...giftConfiguration.boxTypes ]; let newPrev = [ ...giftConfiguration.boxTypes ];
newPrev.push(giftConfiguration.defaultStuffTypes[ Math.floor((Math.random() * (giftConfiguration.defaultStuffTypes.length - 1))) ]); newPrev.push(giftConfiguration.defaultStuffTypes[ Math.floor((Math.random() * (giftConfiguration.defaultStuffTypes.length - 1))) ]);
setMaxBoxIndex(newPrev.length- 1); setMaxBoxIndex(newPrev.length- 1);
setMaxRibbonIndex(newPrev.length - 1); setMaxRibbonIndex(newPrev.length - 1);
return newPrev; return newPrev;
}) })
},[ giftConfiguration ]) },[ giftConfiguration ])
@ -167,9 +195,9 @@ export const CatalogGiftView: FC<{}> = props =>
setColors(newColors); setColors(newColors);
} }
}, [ giftConfiguration, createBoxTypes ]); }, [ giftConfiguration, createBoxTypes ]);
useEffect(() => useEffect(() =>
{ {
if (!isVisible) return; if (!isVisible) return;
createBoxTypes(); createBoxTypes();
@ -187,7 +215,14 @@ export const CatalogGiftView: FC<{}> = props =>
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<FormGroup column> <FormGroup column>
<Text>{ LocalizeText('catalog.gift_wrapping.receiver') }</Text> <Text>{ LocalizeText('catalog.gift_wrapping.receiver') }</Text>
<input type="text" className={ classNames('form-control form-control-sm', receiverNotFound && 'is-invalid') } value={ receiverName } onChange={ (e) => setReceiverName(e.target.value) } /> <input type="text" className={ classNames('form-control form-control-sm', receiverNotFound && 'is-invalid') } value={ receiverName } onChange={ (e) => onTextChanged(e) } />
{ (suggestions.length > 0 && isAutocompleteVisible) &&
<Column className="autocomplete-gift-container">
{ suggestions.map((friend: MessengerFriend) => (
<Base key={ friend.id } className="autocomplete-gift-item" onClick={ (e) => selectedReceiverName(friend.name) }>{ friend.name }</Base>
)) }
</Column>
}
{ receiverNotFound && { receiverNotFound &&
<Base className="invalid-feedback">{ LocalizeText('catalog.gift_wrapping.receiver_not_found.title') }</Base> } <Base className="invalid-feedback">{ LocalizeText('catalog.gift_wrapping.receiver_not_found.title') }</Base> }
</FormGroup> </FormGroup>