1
0
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:
Du Peng 2022-08-25 20:50:15 +02:00
parent d9687a007b
commit 885db68b51
4 changed files with 116 additions and 0 deletions

View 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;
}
}

View File

@ -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() &&

View File

@ -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>
);
};

View File

@ -0,0 +1,8 @@
export interface Coupon {
id: number,
code: string,
type: string,
amount_off: number,
percent_off: number,
validity_per_user: string
}