mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
add coupon component
This commit is contained in:
parent
d9687a007b
commit
885db68b51
10
app/frontend/src/javascript/api/coupon.ts
Normal file
10
app/frontend/src/javascript/api/coupon.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import apiClient from './clients/api-client';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Coupon } from '../models/coupon';
|
||||
|
||||
export default class CouponAPI {
|
||||
static async validate (code: string, amount: number, userId?: number): Promise<Coupon> {
|
||||
const res: AxiosResponse<Coupon> = await apiClient.post('/api/coupons/validate', { code, amount, user_id: userId });
|
||||
return res?.data;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import { PaymentModal } from '../payment/stripe/payment-modal';
|
||||
import { PaymentMethod } from '../../models/payment';
|
||||
import { Order } from '../../models/order';
|
||||
import { MemberSelect } from '../user/member-select';
|
||||
import { CouponInput } from '../coupon/coupon-input';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -117,6 +118,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onError, currentUser }) => {
|
||||
</FabButton>
|
||||
</div>
|
||||
))}
|
||||
{cart && !cartIsEmpty() && <CouponInput user={cart.user} amount={cart.amount} />}
|
||||
{cart && !cartIsEmpty() && <p>Totale: {FormatLib.price(cart.amount)}</p>}
|
||||
{cart && !cartIsEmpty() && isPrivileged() && <MemberSelect defaultUser={cart.user} onSelected={handleChangeMember} />}
|
||||
{cart && !cartIsEmpty() &&
|
||||
|
@ -0,0 +1,96 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FabInput } from '../base/fab-input';
|
||||
import { FabAlert } from '../base/fab-alert';
|
||||
import CouponAPI from '../../api/coupon';
|
||||
import { Coupon } from '../../models/coupon';
|
||||
import { User } from '../../models/user';
|
||||
|
||||
interface CouponInputProps {
|
||||
amount: number,
|
||||
user?: User,
|
||||
onChange?: (coupon: Coupon) => void
|
||||
}
|
||||
|
||||
interface Message {
|
||||
type: 'info' | 'warning' | 'danger',
|
||||
message: string
|
||||
}
|
||||
|
||||
/**
|
||||
* This component renders an input of coupon
|
||||
*/
|
||||
export const CouponInput: React.FC<CouponInputProps> = ({ user, amount, onChange }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
const [messages, setMessages] = useState<Array<Message>>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
const [coupon, setCoupon] = useState<Coupon>();
|
||||
|
||||
/**
|
||||
* callback for validate the code
|
||||
*/
|
||||
const handleChange = (value: string) => {
|
||||
const mgs = [];
|
||||
setMessages([]);
|
||||
setError(false);
|
||||
setCoupon(null);
|
||||
if (value) {
|
||||
setLoading(true);
|
||||
CouponAPI.validate(value, amount, user?.id).then((res) => {
|
||||
setCoupon(res);
|
||||
if (res.type === 'percent_off') {
|
||||
mgs.push({ type: 'info', message: t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_PERCENT_discount', { PERCENT: res.percent_off }) });
|
||||
} else {
|
||||
mgs.push({ type: 'info', message: t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY', { AMOUNT: res.amount_off, CURRENCY: 'euro' }) });
|
||||
}
|
||||
if (res.validity_per_user === 'once') {
|
||||
mgs.push({ type: 'warning', message: t('app.shared.coupon_input.coupon_validity_once') });
|
||||
}
|
||||
setMessages(mgs);
|
||||
setLoading(false);
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(res);
|
||||
}
|
||||
}).catch((err) => {
|
||||
const state = err.split(':')[1].trim();
|
||||
setError(true);
|
||||
setCoupon(null);
|
||||
setLoading(false);
|
||||
setMessages([{ type: 'danger', message: t(`app.shared.coupon_input.unable_to_apply_the_coupon_because_${state}`) }]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// input addon
|
||||
const inputAddOn = () => {
|
||||
if (error) {
|
||||
return <i className="fa fa-times" />;
|
||||
} else {
|
||||
if (loading) {
|
||||
return <i className="fa fa-spinner fa-pulse fa-fw" />;
|
||||
}
|
||||
if (coupon) {
|
||||
return <i className="fa fa-check" />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="coupon-input">
|
||||
<label htmlFor="coupon-input_input">{t('app.shared.coupon_input.i_have_a_coupon')}</label>
|
||||
<FabInput id="coupon-input_input"
|
||||
type="text"
|
||||
addOn={inputAddOn()}
|
||||
debounce={500}
|
||||
onChange={handleChange} />
|
||||
{messages.map((m, i) => {
|
||||
return (
|
||||
<FabAlert key={i} level={m.type}>
|
||||
{m.message}
|
||||
</FabAlert>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
8
app/frontend/src/javascript/models/coupon.ts
Normal file
8
app/frontend/src/javascript/models/coupon.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface Coupon {
|
||||
id: number,
|
||||
code: string,
|
||||
type: string,
|
||||
amount_off: number,
|
||||
percent_off: number,
|
||||
validity_per_user: string
|
||||
}
|
Loading…
Reference in New Issue
Block a user