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:
parent
f3a2136e7d
commit
a10e75844a
@ -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() && <>
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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";
|
||||
|
||||
|
26
app/frontend/src/stylesheets/modules/user/member-select.scss
Normal file
26
app/frontend/src/stylesheets/modules/user/member-select.scss
Normal 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); }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user