mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
Add pet name approval
This commit is contained in:
parent
058f8e6dcc
commit
f56164e3c2
@ -9,4 +9,5 @@ export class CatalogEvent extends NitroEvent
|
|||||||
public static PURCHASE_FAILED: string = 'CE_PURCHASE_FAILED';
|
public static PURCHASE_FAILED: string = 'CE_PURCHASE_FAILED';
|
||||||
public static SOLD_OUT: string = 'CE_SOLD_OUT';
|
public static SOLD_OUT: string = 'CE_SOLD_OUT';
|
||||||
public static APPROVE_NAME_RESULT: string = 'CE_APPROVE_NAME_RESULT';
|
public static APPROVE_NAME_RESULT: string = 'CE_APPROVE_NAME_RESULT';
|
||||||
|
public static PURCHASE_APPROVED: string = 'CE_PURCHASE_APPROVED';
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,31 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
|
|||||||
return LocalizeText(`pet.breed.${ petIndex }.${ sellablePalettes[selectedPaletteIndex].breedId }`);
|
return LocalizeText(`pet.breed.${ petIndex }.${ sellablePalettes[selectedPaletteIndex].breedId }`);
|
||||||
}, [ petIndex, sellablePalettes, selectedPaletteIndex ]);
|
}, [ petIndex, sellablePalettes, selectedPaletteIndex ]);
|
||||||
|
|
||||||
|
const petPurchaseString = useMemo(() =>
|
||||||
|
{
|
||||||
|
if(!sellablePalettes.length || (selectedPaletteIndex === -1)) return '';
|
||||||
|
|
||||||
|
const paletteId = sellablePalettes[selectedPaletteIndex].paletteId;
|
||||||
|
|
||||||
|
let color = 0xFFFFFF;
|
||||||
|
|
||||||
|
if(petIndex <= 7)
|
||||||
|
{
|
||||||
|
if(selectedColorIndex === -1) return '';
|
||||||
|
|
||||||
|
color = sellableColors[selectedColorIndex][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorString = color.toString(16).toUpperCase();
|
||||||
|
|
||||||
|
while(colorString.length < 6)
|
||||||
|
{
|
||||||
|
colorString = ('0' + colorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${ paletteId }\n${ colorString }`;
|
||||||
|
}, [ sellablePalettes, selectedPaletteIndex, petIndex, sellableColors, selectedColorIndex ]);
|
||||||
|
|
||||||
if(!activeOffer) return null;
|
if(!activeOffer) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -143,7 +168,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
|
|||||||
</button> }
|
</button> }
|
||||||
</RoomPreviewerView>
|
</RoomPreviewerView>
|
||||||
<div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div>
|
<div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div>
|
||||||
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } />
|
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,61 @@
|
|||||||
import { FC } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { CatalogEvent, CatalogNameResultEvent } from '../../../../../../../events';
|
||||||
|
import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event';
|
||||||
import { LocalizeText } from '../../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../../utils/LocalizeText';
|
||||||
import { CatalogPetNameApprovalViewProps } from './CatalogPetNameApprovalView.types';
|
import { CatalogPetNameApprovalViewProps } from './CatalogPetNameApprovalView.types';
|
||||||
|
|
||||||
export const CatalogPetNameApprovalView: FC<CatalogPetNameApprovalViewProps> = props =>
|
export const CatalogPetNameApprovalView: FC<CatalogPetNameApprovalViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { petNameValue = null, setPetNameValue = null } = props;
|
const { petNameValue = null, setPetNameValue = null, nameApproved = false, setNameApproved = null } = props;
|
||||||
|
const [ validationResult, setValidationResult ] = useState(-1);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setValidationResult(-1);
|
||||||
|
}, [ petNameValue ]);
|
||||||
|
|
||||||
|
const onCatalogNameResultEvent = useCallback((event: CatalogNameResultEvent) =>
|
||||||
|
{
|
||||||
|
if(event.result === 0)
|
||||||
|
{
|
||||||
|
setNameApproved(true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValidationResult(event.result);
|
||||||
|
}, [ setNameApproved ]);
|
||||||
|
|
||||||
|
useUiEvent(CatalogEvent.APPROVE_NAME_RESULT, onCatalogNameResultEvent);
|
||||||
|
|
||||||
|
const validationErrorMessage = useMemo(() =>
|
||||||
|
{
|
||||||
|
let key: string = '';
|
||||||
|
|
||||||
|
switch(validationResult)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
key = 'catalog.alert.petname.long';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
key = 'catalog.alert.petname.short';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
key = 'catalog.alert.petname.chars';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
key = 'catalog.alert.petname.bobba';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LocalizeText(key);
|
||||||
|
}, [ validationResult ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('widgets.petpackage.name.title') } value={ petNameValue } onChange={ event => setPetNameValue(event.target.value) } />
|
<div className="input-group has-validation">
|
||||||
|
<input type="text" className={ 'form-control form-control-sm '+ ((validationResult > 0) ? 'is-invalid ' : '') } placeholder={ LocalizeText('widgets.petpackage.name.title') } value={ petNameValue } onChange={ event => setPetNameValue(event.target.value) } />
|
||||||
|
{ (validationResult > 0) &&
|
||||||
|
<div className="invalid-feedback">{ validationErrorMessage }</div> }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,6 @@ export interface CatalogPetNameApprovalViewProps
|
|||||||
{
|
{
|
||||||
petNameValue: string;
|
petNameValue: string;
|
||||||
setPetNameValue: Dispatch<SetStateAction<string>>;
|
setPetNameValue: Dispatch<SetStateAction<string>>;
|
||||||
|
nameApproved: boolean;
|
||||||
|
setNameApproved: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { FC, useState } from 'react';
|
import { ApproveNameMessageComposer } from 'nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { CatalogEvent } from '../../../../../../../events';
|
||||||
|
import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event';
|
||||||
|
import { SendMessageHook } from '../../../../../../../hooks/messages/message-event';
|
||||||
import { CurrencyIcon } from '../../../../../../../utils/currency-icon/CurrencyIcon';
|
import { CurrencyIcon } from '../../../../../../../utils/currency-icon/CurrencyIcon';
|
||||||
import { LocalizeText } from '../../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../../utils/LocalizeText';
|
||||||
import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView';
|
import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView';
|
||||||
@ -9,13 +13,31 @@ export const CatalogLayoutPetPurchaseView: FC<CatalogLayoutPetPurchaseViewProps>
|
|||||||
{
|
{
|
||||||
const { offer = null, pageId = -1, extra = '' } = props;
|
const { offer = null, pageId = -1, extra = '' } = props;
|
||||||
const [ petNameValue, setPetNameValue ] = useState('');
|
const [ petNameValue, setPetNameValue ] = useState('');
|
||||||
|
const [ nameApproved, setNameApproved ] = useState(false);
|
||||||
|
|
||||||
const extraData = ((extra && extra.length) ? extra : (offer?.products[0]?.extraParam || null));
|
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||||
|
{
|
||||||
|
switch(event.type)
|
||||||
|
{
|
||||||
|
case CatalogEvent.PURCHASE_SUCCESS:
|
||||||
|
setNameApproved(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent);
|
||||||
|
|
||||||
|
const beforePurchase = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new ApproveNameMessageComposer(petNameValue, 1));
|
||||||
|
}, [ petNameValue ]);
|
||||||
|
|
||||||
|
const extraData = `${ petNameValue }\n${ extra }`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="d-flex flex-grow-1 justify-content-center align-items-center">
|
<div className="d-flex flex-grow-1 justify-content-center align-items-center">
|
||||||
<CatalogPetNameApprovalView petNameValue={ petNameValue } setPetNameValue={ setPetNameValue } />
|
<CatalogPetNameApprovalView petNameValue={ petNameValue } setPetNameValue={ setPetNameValue } nameApproved={ nameApproved } setNameApproved={ setNameApproved } />
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex flex-column flex-grow-1 justify-content-end w-100">
|
<div className="d-flex flex-column flex-grow-1 justify-content-end w-100">
|
||||||
<div className="d-flex align-items-end">
|
<div className="d-flex align-items-end">
|
||||||
@ -36,7 +58,7 @@ export const CatalogLayoutPetPurchaseView: FC<CatalogLayoutPetPurchaseViewProps>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex flex-column mt-1">
|
<div className="d-flex flex-column mt-1">
|
||||||
<CatalogPurchaseButtonView className="btn-sm w-100" offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } />
|
<CatalogPurchaseButtonView className="btn-sm w-100" offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } isPurchaseAllowed={ nameApproved } beforePurchase={ beforePurchase } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -10,8 +10,9 @@ import { CatalogPurchaseButtonViewProps, CatalogPurchaseState } from './CatalogP
|
|||||||
|
|
||||||
export const CatalogPurchaseButtonView: FC<CatalogPurchaseButtonViewProps> = props =>
|
export const CatalogPurchaseButtonView: FC<CatalogPurchaseButtonViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { className = '', offer = null, pageId = -1, extra = null, quantity = 1 } = props;
|
const { className = '', offer = null, pageId = -1, extra = null, quantity = 1, isPurchaseAllowed = true, beforePurchase = null } = props;
|
||||||
const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE);
|
const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE);
|
||||||
|
const [ pendingApproval, setPendingApproval ] = useState(false);
|
||||||
|
|
||||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||||
{
|
{
|
||||||
@ -31,16 +32,43 @@ export const CatalogPurchaseButtonView: FC<CatalogPurchaseButtonViewProps> = pro
|
|||||||
|
|
||||||
const purchase = useCallback(() =>
|
const purchase = useCallback(() =>
|
||||||
{
|
{
|
||||||
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
|
||||||
|
|
||||||
SendMessageHook(new CatalogPurchaseComposer(pageId, offer.offerId, extra, quantity));
|
SendMessageHook(new CatalogPurchaseComposer(pageId, offer.offerId, extra, quantity));
|
||||||
}, [ pageId, offer, extra, quantity ]);
|
}, [ pageId, offer, extra, quantity ]);
|
||||||
|
|
||||||
|
const attemptPurchase = useCallback(() =>
|
||||||
|
{
|
||||||
|
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
||||||
|
|
||||||
|
if(beforePurchase) beforePurchase();
|
||||||
|
|
||||||
|
if(!isPurchaseAllowed)
|
||||||
|
{
|
||||||
|
setPendingApproval(true);
|
||||||
|
setPurchaseState(CatalogPurchaseState.NONE);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
purchase();
|
||||||
|
}, [ isPurchaseAllowed, beforePurchase, purchase ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setPurchaseState(CatalogPurchaseState.NONE);
|
setPurchaseState(CatalogPurchaseState.NONE);
|
||||||
}, [ offer, quantity ]);
|
}, [ offer, quantity ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(pendingApproval && isPurchaseAllowed)
|
||||||
|
{
|
||||||
|
setPendingApproval(false);
|
||||||
|
|
||||||
|
purchase();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, [ purchaseState, pendingApproval, isPurchaseAllowed, purchase ]);
|
||||||
|
|
||||||
const product = offer.products[0];
|
const product = offer.products[0];
|
||||||
|
|
||||||
if(product && product.uniqueLimitedItem && !product.uniqueLimitedItemsLeft)
|
if(product && product.uniqueLimitedItem && !product.uniqueLimitedItemsLeft)
|
||||||
@ -61,7 +89,7 @@ export const CatalogPurchaseButtonView: FC<CatalogPurchaseButtonViewProps> = pro
|
|||||||
switch(purchaseState)
|
switch(purchaseState)
|
||||||
{
|
{
|
||||||
case CatalogPurchaseState.CONFIRM:
|
case CatalogPurchaseState.CONFIRM:
|
||||||
return <button type="button" className={ 'btn btn-warning ' + className } onClick={ purchase }>{ LocalizeText('catalog.marketplace.confirm_title') }</button>;
|
return <button type="button" className={ 'btn btn-warning ' + className } onClick={ attemptPurchase }>{ LocalizeText('catalog.marketplace.confirm_title') }</button>;
|
||||||
case CatalogPurchaseState.PURCHASE:
|
case CatalogPurchaseState.PURCHASE:
|
||||||
return <button type="button" className={ 'btn btn-primary ' + className } disabled><LoadingSpinnerView /></button>;
|
return <button type="button" className={ 'btn btn-primary ' + className } disabled><LoadingSpinnerView /></button>;
|
||||||
case CatalogPurchaseState.SOLD_OUT:
|
case CatalogPurchaseState.SOLD_OUT:
|
||||||
|
@ -7,6 +7,8 @@ export interface CatalogPurchaseButtonViewProps
|
|||||||
pageId: number;
|
pageId: number;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
quantity?: number;
|
quantity?: number;
|
||||||
|
isPurchaseAllowed?: boolean;
|
||||||
|
beforePurchase?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CatalogPurchaseState
|
export class CatalogPurchaseState
|
||||||
|
Loading…
Reference in New Issue
Block a user