mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-01 12:24:28 +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 { PaymentMethod } from '../../models/payment';
|
||||||
import { Order } from '../../models/order';
|
import { Order } from '../../models/order';
|
||||||
import { MemberSelect } from '../user/member-select';
|
import { MemberSelect } from '../user/member-select';
|
||||||
|
import { CouponInput } from '../coupon/coupon-input';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onError, currentUser }) => {
|
|||||||
</FabButton>
|
</FabButton>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
{cart && !cartIsEmpty() && <CouponInput user={cart.user} amount={cart.amount} />}
|
||||||
{cart && !cartIsEmpty() && <p>Totale: {FormatLib.price(cart.amount)}</p>}
|
{cart && !cartIsEmpty() && <p>Totale: {FormatLib.price(cart.amount)}</p>}
|
||||||
{cart && !cartIsEmpty() && isPrivileged() && <MemberSelect defaultUser={cart.user} onSelected={handleChangeMember} />}
|
{cart && !cartIsEmpty() && isPrivileged() && <MemberSelect defaultUser={cart.user} onSelected={handleChangeMember} />}
|
||||||
{cart && !cartIsEmpty() &&
|
{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