Commit ec458499 by asranov0003

feat: add billing pay

parent 85392706
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
import { import {
fetchPaymentMethods, fetchPaymentMethods,
fetchTariffs, fetchTariffs,
pay,
} from "../../stores/slices/billingSlice"; } from "../../stores/slices/billingSlice";
import type { IPaymentMethod, ITariff } from "../../types/billing.types"; import type { IPaymentMethod, ITariff } from "../../types/billing.types";
import CLoading from "../../components/CLoading"; import CLoading from "../../components/CLoading";
...@@ -18,8 +19,14 @@ const Subscription: React.FC = () => { ...@@ -18,8 +19,14 @@ const Subscription: React.FC = () => {
const [selectedTariff, setSelectedTariff] = useState<ITariff | null>(null); const [selectedTariff, setSelectedTariff] = useState<ITariff | null>(null);
const [selectedPaymentMethod, setSelectedPaymentMethod] = const [selectedPaymentMethod, setSelectedPaymentMethod] =
useState<IPaymentMethod | null>(null); useState<IPaymentMethod | null>(null);
const { tariffs, paymentMethods, isTariffsLoading, isPaymentMethodsLoading } = const {
useAppSelector((state: RootState) => state.billing); tariffs,
paymentMethods,
isTariffsLoading,
isPaymentMethodsLoading,
payUrl,
isPayLoading,
} = useAppSelector((state: RootState) => state.billing);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
...@@ -40,6 +47,25 @@ const Subscription: React.FC = () => { ...@@ -40,6 +47,25 @@ const Subscription: React.FC = () => {
} }
}, [paymentMethods]); }, [paymentMethods]);
useEffect(() => {
if (payUrl) {
window.location.href = payUrl;
}
}, [payUrl]);
const handlePay = () => {
if (!selectedTariff || !selectedPaymentMethod) {
return;
}
dispatch(
pay({
paymentMethodId: selectedPaymentMethod.id,
payMonths: selectedTariff.payMonths,
})
);
};
return ( return (
<div className="subscription wrapper"> <div className="subscription wrapper">
{isTariffsLoading && {isTariffsLoading &&
...@@ -101,7 +127,11 @@ const Subscription: React.FC = () => { ...@@ -101,7 +127,11 @@ const Subscription: React.FC = () => {
</div> </div>
</div> </div>
<CButton title={t("subscription.pay")} /> <CButton
title={t("subscription.pay")}
onClick={handlePay}
isLoading={isPayLoading}
/>
</div> </div>
); );
}; };
......
...@@ -9,6 +9,8 @@ interface IBillingState { ...@@ -9,6 +9,8 @@ interface IBillingState {
paymentMethods: IPaymentMethod[]; paymentMethods: IPaymentMethod[];
isPaymentMethodsLoading: boolean; isPaymentMethodsLoading: boolean;
paymentMethodsError: string | null; paymentMethodsError: string | null;
payUrl: string;
isPayLoading: boolean;
} }
const initialState: IBillingState = { const initialState: IBillingState = {
...@@ -18,6 +20,8 @@ const initialState: IBillingState = { ...@@ -18,6 +20,8 @@ const initialState: IBillingState = {
paymentMethods: [], paymentMethods: [],
isPaymentMethodsLoading: false, isPaymentMethodsLoading: false,
paymentMethodsError: null, paymentMethodsError: null,
payUrl: "",
isPayLoading: false,
}; };
export const fetchTariffs = createAsyncThunk( export const fetchTariffs = createAsyncThunk(
...@@ -58,6 +62,31 @@ export const fetchPaymentMethods = createAsyncThunk( ...@@ -58,6 +62,31 @@ export const fetchPaymentMethods = createAsyncThunk(
} }
); );
export const pay = createAsyncThunk(
"billing/pay",
async (
{
payMonths,
paymentMethodId,
}: { payMonths: string; paymentMethodId: string },
{ rejectWithValue }
) => {
try {
const response = await sendRpcRequest<{ url: string }>("billing.pay", {
methodId: paymentMethodId,
months: payMonths,
});
return response.url;
} catch (error: unknown) {
if (typeof error === "object" && error !== null && "message" in error) {
return rejectWithValue(error.message);
}
return rejectWithValue("Unknown error occurred");
}
}
);
const billingSlice = createSlice({ const billingSlice = createSlice({
name: "billing", name: "billing",
initialState, initialState,
...@@ -88,6 +117,19 @@ const billingSlice = createSlice({ ...@@ -88,6 +117,19 @@ const billingSlice = createSlice({
.addCase(fetchPaymentMethods.rejected, (state, action) => { .addCase(fetchPaymentMethods.rejected, (state, action) => {
state.isPaymentMethodsLoading = false; state.isPaymentMethodsLoading = false;
state.paymentMethodsError = action.payload as string; state.paymentMethodsError = action.payload as string;
})
.addCase(pay.pending, (state) => {
state.isPayLoading = true;
state.payUrl = "";
})
.addCase(pay.fulfilled, (state, action) => {
state.isPayLoading = false;
state.payUrl = action.payload;
})
.addCase(pay.rejected, (state, action) => {
state.isPayLoading = false;
state.payUrl = action.payload as string;
}); });
}, },
}); });
......
...@@ -2,6 +2,7 @@ export interface ITariff { ...@@ -2,6 +2,7 @@ export interface ITariff {
id: string; id: string;
title: string; title: string;
amount: string; amount: string;
payMonths: string;
} }
export interface IPaymentMethod { export interface IPaymentMethod {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment