1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-26 20:54:21 +01:00

(feat) visual indicator if no user selected

This commit is contained in:
Sylvain 2022-10-04 10:51:32 +02:00
parent f3a2136e7d
commit a10e75844a
4 changed files with 40 additions and 4 deletions

View File

@ -39,6 +39,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
const { cart, setCart, reloadCart } = useCart(currentUser);
const [cartErrors, setCartErrors] = useState<OrderErrors>(null);
const [noMemberError, setNoMemberError] = useState<boolean>(false);
const [paymentModal, setPaymentModal] = useState<boolean>(false);
const [settings, setSettings] = useState<Map<SettingName, string>>(null);
@ -124,8 +125,10 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
userLogin();
} else {
if (!cart.user) {
setNoMemberError(true);
onError(t('app.public.store_cart.select_user'));
} else {
setNoMemberError(false);
checkCart().then(errors => {
if (!hasCartErrors(errors)) {
setPaymentModal(true);
@ -328,7 +331,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
<aside>
{cart && !cartIsEmpty() && isPrivileged() &&
<div> <MemberSelect onSelected={handleChangeMember} defaultUser={cart.user as User} /></div>
<div> <MemberSelect onSelected={handleChangeMember} defaultUser={cart.user as User} hasError={noMemberError} /></div>
}
{cart && !cartIsEmpty() && <>

View File

@ -8,7 +8,8 @@ interface MemberSelectProps {
defaultUser?: User,
value?: User,
onSelected?: (user: { id: number, name: string }) => void,
noHeader?: boolean
noHeader?: boolean,
hasError?: boolean
}
/**
@ -20,7 +21,7 @@ type selectOption = { value: number, label: string };
/**
* This component renders the member select for manager.
*/
export const MemberSelect: React.FC<MemberSelectProps> = ({ defaultUser, value, onSelected, noHeader }) => {
export const MemberSelect: React.FC<MemberSelectProps> = ({ defaultUser, value, onSelected, noHeader, hasError }) => {
const { t } = useTranslation('public');
const [option, setOption] = useState<selectOption>();
@ -67,13 +68,14 @@ export const MemberSelect: React.FC<MemberSelectProps> = ({ defaultUser, value,
};
return (
<div className="member-select">
<div className={`member-select ${hasError ? 'error' : ''}`}>
{!noHeader &&
<div className="member-select-header">
<h3 className="member-select-title">{t('app.public.member_select.select_a_member')}</h3>
</div>
}
<AsyncSelect placeholder={t('app.public.member_select.start_typing')}
className="select-input"
cacheOptions
loadOptions={loadMembers}
defaultOptions
@ -83,3 +85,7 @@ export const MemberSelect: React.FC<MemberSelectProps> = ({ defaultUser, value,
</div>
);
};
MemberSelect.defaultProps = {
hasError: false
};

View File

@ -120,6 +120,7 @@
@import "modules/user/avatar";
@import "modules/user/avatar-input";
@import "modules/user/gender-input";
@import "modules/user/member-select";
@import "modules/user/user-profile-form";
@import "modules/user/user-validation";

View File

@ -0,0 +1,26 @@
.member-select {
&.error {
.select-input > div {
border-color: var(--alert);
transform: perspective(1px) translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
animation-name: buzz-out;
animation-duration: 0.75s;
animation-timing-function: linear;
animation-iteration-count: 1;
}
}
}
@keyframes buzz-out {
10% { transform: translateX(3px) rotate(2deg); }
20% { transform: translateX(-3px) rotate(-2deg); }
30% { transform: translateX(3px) rotate(2deg); }
40% { transform: translateX(-3px) rotate(-2deg); }
50% { transform: translateX(2px) rotate(1deg); }
60% { transform: translateX(-2px) rotate(-1deg); }
70% { transform: translateX(2px) rotate(1deg); }
80% { transform: translateX(-2px) rotate(-1deg); }
90% { transform: translateX(1px) rotate(0); }
100% { transform: translateX(-1px) rotate(0); }
}