Commit ec458499 by asranov0003

feat: add billing pay

parent 85392706
......@@ -10,6 +10,7 @@ import {
import {
fetchPaymentMethods,
fetchTariffs,
pay,
} from "../../stores/slices/billingSlice";
import type { IPaymentMethod, ITariff } from "../../types/billing.types";
import CLoading from "../../components/CLoading";
......@@ -18,8 +19,14 @@ const Subscription: React.FC = () => {
const [selectedTariff, setSelectedTariff] = useState<ITariff | null>(null);
const [selectedPaymentMethod, setSelectedPaymentMethod] =
useState<IPaymentMethod | null>(null);
const { tariffs, paymentMethods, isTariffsLoading, isPaymentMethodsLoading } =
useAppSelector((state: RootState) => state.billing);
const {
tariffs,
paymentMethods,
isTariffsLoading,
isPaymentMethodsLoading,
payUrl,
isPayLoading,
} = useAppSelector((state: RootState) => state.billing);
const dispatch = useAppDispatch();
const { t } = useTranslation();
......@@ -40,6 +47,25 @@ const Subscription: React.FC = () => {
}
}, [paymentMethods]);
useEffect(() => {
if (payUrl) {
window.location.href = payUrl;
}
}, [payUrl]);
const handlePay = () => {
if (!selectedTariff || !selectedPaymentMethod) {
return;
}
dispatch(
pay({
paymentMethodId: selectedPaymentMethod.id,
payMonths: selectedTariff.payMonths,
})
);
};
return (
<div className="subscription wrapper">
{isTariffsLoading &&
......@@ -101,7 +127,11 @@ const Subscription: React.FC = () => {
</div>
</div>
<CButton title={t("subscription.pay")} />
<CButton
title={t("subscription.pay")}
onClick={handlePay}
isLoading={isPayLoading}
/>
</div>
);
};
......
......@@ -9,6 +9,8 @@ interface IBillingState {
paymentMethods: IPaymentMethod[];
isPaymentMethodsLoading: boolean;
paymentMethodsError: string | null;
payUrl: string;
isPayLoading: boolean;
}
const initialState: IBillingState = {
......@@ -18,6 +20,8 @@ const initialState: IBillingState = {
paymentMethods: [],
isPaymentMethodsLoading: false,
paymentMethodsError: null,
payUrl: "",
isPayLoading: false,
};
export const fetchTariffs = 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({
name: "billing",
initialState,
......@@ -88,6 +117,19 @@ const billingSlice = createSlice({
.addCase(fetchPaymentMethods.rejected, (state, action) => {
state.isPaymentMethodsLoading = false;
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 {
id: string;
title: string;
amount: string;
payMonths: string;
}
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