feature: change from monthly to annual plan
This commit is contained in:
parent
49dc765254
commit
de82cf813f
@ -34,8 +34,6 @@ export const actions = {
|
|||||||
const apiKey = import.meta.env.VITE_LEMON_SQUEEZY_API_KEY;
|
const apiKey = import.meta.env.VITE_LEMON_SQUEEZY_API_KEY;
|
||||||
const subscriptionId = formData?.get('subscriptionId');
|
const subscriptionId = formData?.get('subscriptionId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `https://api.lemonsqueezy.com/v1/subscriptions/${subscriptionId}`;
|
const url = `https://api.lemonsqueezy.com/v1/subscriptions/${subscriptionId}`;
|
||||||
const headers = {
|
const headers = {
|
||||||
@ -49,8 +47,6 @@ export const actions = {
|
|||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Error: ", err);
|
console.log("Error: ", err);
|
||||||
error(err.status, err.message);
|
error(err.status, err.message);
|
||||||
@ -105,6 +101,50 @@ export const actions = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
changeSubscription: async ({ request, locals }) => {
|
||||||
|
const formData = await request?.formData();
|
||||||
|
|
||||||
|
const apiKey = import.meta.env.VITE_LEMON_SQUEEZY_API_KEY;
|
||||||
|
const subscriptionId = formData?.get('subscriptionId');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = `https://api.lemonsqueezy.com/v1/subscriptions/${subscriptionId}`;
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/vnd.api+json',
|
||||||
|
'Content-Type': 'application/vnd.api+json',
|
||||||
|
'Authorization': `Bearer ${apiKey}`
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the data payload
|
||||||
|
const payload = {
|
||||||
|
data: {
|
||||||
|
type: "subscriptions",
|
||||||
|
id: subscriptionId,
|
||||||
|
attributes: {
|
||||||
|
variant_id: import.meta.env.VITE_LEMON_SQUEEZY_ANNUAL_VARIANT_ID // Change from monthly to annually plan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: headers,
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(await response.json())
|
||||||
|
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error: ", err);
|
||||||
|
error(err.status, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
redirect(302, '/community/profile');
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
import { pb } from '$lib/pocketbase';
|
import { pb } from '$lib/pocketbase';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { updatePersonalDataSchema, updatePasswordSchema} from '$lib/schemas';
|
import { updatePersonalDataSchema, updatePasswordSchema} from '$lib/schemas';
|
||||||
import communityBanner from '$lib/images/community_banner.jpg';
|
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
@ -147,21 +146,48 @@ setTimeout(() => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function handleReactivateSubscription() {
|
const submitChangePlan = () => {
|
||||||
|
return async ({ result, update}) => {
|
||||||
|
switch (result.type) {
|
||||||
|
case 'success':
|
||||||
|
toast.success('Changing to Annual Plan successfully!', {
|
||||||
|
style: 'border-radius: 200px; background: #333; color: #fff;'});
|
||||||
|
await update();
|
||||||
|
break;
|
||||||
|
case 'redirect':
|
||||||
|
toast.success('Changing to Annual Plan successfully!', {
|
||||||
|
style: 'border-radius: 200px; background: #333; color: #fff;'});
|
||||||
|
await update();
|
||||||
|
break;
|
||||||
|
case 'failure':
|
||||||
|
toast.error('Something went wrong.', {
|
||||||
|
style: 'border-radius: 200px; background: #333; color: #fff;'});
|
||||||
|
await update();
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
toast.error(result.error.message, {
|
||||||
|
style: 'border-radius: 200px; background: #333; color: #fff;'});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await update();
|
||||||
|
}
|
||||||
|
|
||||||
// make the POST request to the endpoint
|
setTimeout(() => {
|
||||||
const response = await fetch('/api/reactivate-subscription', {
|
if (result.type === 'redirect') {
|
||||||
method: 'GET',
|
const anchor = document.createElement('a');
|
||||||
headers: {
|
anchor.href = '/community/profile';
|
||||||
'Content-Type': 'application/json',
|
anchor.dataset.sveltekitReload = true;
|
||||||
},
|
document.body.appendChild(anchor);
|
||||||
});
|
anchor.dispatchEvent(new MouseEvent('click'));
|
||||||
|
}
|
||||||
const output = await response.json();
|
}, 5000);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function updateAvatar(event)
|
async function updateAvatar(event)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -446,7 +472,7 @@ async function getPost() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let showTab = 'post';
|
let showTab = 'subscription';
|
||||||
|
|
||||||
let settingsTab = 'personalData';
|
let settingsTab = 'personalData';
|
||||||
|
|
||||||
@ -897,9 +923,18 @@ onDestroy(async () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if subscriptionData?.status_formatted === 'Active' || subscriptionData?.status_formatted === 'On Trial'}
|
{#if subscriptionData?.status_formatted === 'Active' || subscriptionData?.status_formatted === 'On Trial'}
|
||||||
<label for="cancelSubscriptionModal" class="cursor-pointer text-white bg-[#FF3131] hover:bg-red-600 bg-opacity-[0.5] text-sm sm:text-[1rem] px-4 py-2 rounded-lg mt-5">
|
<div class="flex flex-col items-start sm:flex-row sm:items-center">
|
||||||
Cancel Subscription
|
<label for="cancelSubscriptionModal" class="cursor-pointer text-white bg-[#FF3131] sm:hover:bg-red-600 bg-opacity-[0.5] text-sm sm:text-[1rem] px-4 py-2 rounded-lg mt-5">
|
||||||
</label>
|
Cancel Subscription
|
||||||
|
</label>
|
||||||
|
{#if subscriptionData?.product_name?.includes('Monthly')}
|
||||||
|
<label for="changeSubscriptionModal" class="sm:ml-3 cursor-pointer text-black bg-[#0DDE00] text-sm sm:text-[1rem] px-4 py-2 rounded-lg mt-5">
|
||||||
|
Change to Annual Plan
|
||||||
|
</label>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{:else if subscriptionData?.status_formatted === 'Cancelled'}
|
{:else if subscriptionData?.status_formatted === 'Cancelled'}
|
||||||
<label for="reactivateSubscriptionModal" class="cursor-pointer text-white bg-[#75D377] bg-opacity-[0.5] text-sm sm:text-[1rem] px-4 py-2 rounded-lg mt-5">
|
<label for="reactivateSubscriptionModal" class="cursor-pointer text-white bg-[#75D377] bg-opacity-[0.5] text-sm sm:text-[1rem] px-4 py-2 rounded-lg mt-5">
|
||||||
Reactivate Subscription
|
Reactivate Subscription
|
||||||
@ -1061,3 +1096,41 @@ onDestroy(async () => {
|
|||||||
</dialog>
|
</dialog>
|
||||||
<!-- End Reactivate Subscription Modal -->
|
<!-- End Reactivate Subscription Modal -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Start Cancel Subscription Modal -->
|
||||||
|
<input type="checkbox" id="changeSubscriptionModal" class="modal-toggle" />
|
||||||
|
|
||||||
|
<dialog id="changeSubscriptionModal" class="modal modal-bottom sm:modal-middle">
|
||||||
|
|
||||||
|
|
||||||
|
<label for="changeSubscriptionModal" class="cursor-pointer modal-backdrop bg-[#000] bg-opacity-[0.5]"></label>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Desktop modal content -->
|
||||||
|
<form method="POST" action="?/changeSubscription" use:enhance={submitChangePlan} class="modal-box w-full bg-[#202020] flex flex-col items-center">
|
||||||
|
<div class="mx-auto mb-8 h-1.5 w-20 flex-shrink-0 rounded-full bg-[#404040]" />
|
||||||
|
<div class="text-white mb-5 text-center">
|
||||||
|
<h3 class="font-bold text-2xl mb-5">Are you sure?</h3>
|
||||||
|
<span class="text-white text-[1rem] font-normal">
|
||||||
|
You're account will transfer from from monthly plan to annual plan.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button on:click={() => isClicked = !isClicked} class="{!isClicked ? '' : 'hidden'} cursor-pointer px-7 py-2 mb-5 rounded-full bg-[#0DDE00] text-center text-black text-[1rem] font-normal">
|
||||||
|
Change to Annual Plan
|
||||||
|
<input class="hidden" name='subscriptionId' value={subscriptionData?.first_subscription_item?.subscription_id}/>
|
||||||
|
</button>
|
||||||
|
{#if isClicked === true}
|
||||||
|
<label class="cursor-pointer px-7 py-2 mb-5 rounded-full bg-[#0DDE00] text-center text-black text-[1rem] font-normal">
|
||||||
|
<div class="flex flex-row m-auto">
|
||||||
|
<span class="loading loading-infinity"></span>
|
||||||
|
<span class="text-black ml-2">Proceeding</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
<!-- End Cancel Subscription Modal -->
|
||||||
@ -128,7 +128,7 @@ async function purchasePlan() {
|
|||||||
Pay Yearly
|
Pay Yearly
|
||||||
</span>
|
</span>
|
||||||
<span class="text-[#10DB06] text-sm font-bold text-opacity-[0.8]">
|
<span class="text-[#10DB06] text-sm font-bold text-opacity-[0.8]">
|
||||||
Save up 25%
|
Save up 22%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -250,16 +250,11 @@ async function purchasePlan() {
|
|||||||
<div class="flex flex-col mb-6 items-center">
|
<div class="flex flex-col mb-6 items-center">
|
||||||
|
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<span class="mr-2 text-4xl font-bold">{mode ? '$7.50' : '$9.99'}</span>
|
<span class="mr-2 text-4xl font-bold">{mode ? '$499' : '$49.99'}</span>
|
||||||
<span class="text-white text-xl">/month</span>
|
<span class="text-white text-xl">{mode ? '/year' : '/month'}</span>
|
||||||
</div>
|
</div>
|
||||||
{#if mode}
|
|
||||||
<div class="flex flex-row items-center justify-start mt-2">
|
<!--
|
||||||
<span class="text-white text-sm">
|
|
||||||
Billed $90 annually
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div class="flex items-center mt-2 text-[1rem] text-center">
|
<div class="flex items-center mt-2 text-[1rem] text-center">
|
||||||
only ${mode ? (7.5/4)?.toFixed(2) : (9.99/4)?.toFixed(2)} / week, less than a
|
only ${mode ? (7.5/4)?.toFixed(2) : (9.99/4)?.toFixed(2)} / week, less than a
|
||||||
{#if mode}
|
{#if mode}
|
||||||
@ -268,6 +263,7 @@ async function purchasePlan() {
|
|||||||
<svg class="w-6 h-6 inline-block ml-2" viewBox="0 0 47.5 47.5" id="svg2" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" fill="#ffffff"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <defs id="defs6"> <clipPath clipPathUnits="userSpaceOnUse" id="clipPath16"> <path d="M 0,38 38,38 38,0 0,0 0,38 Z" id="path18"></path> </clipPath> <clipPath clipPathUnits="userSpaceOnUse" id="clipPath40"> <path d="M 0,38 38,38 38,0 0,0 0,38 Z" id="path42"></path> </clipPath> </defs> <g id="g10" transform="matrix(1.25,0,0,-1.25,0,47.5)"> <g id="g12"> <g clip-path="url(#clipPath16)" id="g14"> <g id="g20" transform="translate(37,11)"> <path d="m 0,0 c 0,-5.522 -8.059,-10 -18,-10 -9.941,0 -18,4.478 -18,10 0,5.522 8.059,10 18,10 C -8.059,10 0,5.522 0,0" id="path22" style="fill:#99aab5;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g24" transform="translate(37,13)"> <path d="m 0,0 c 0,-5.522 -8.059,-10 -18,-10 -9.941,0 -18,4.478 -18,10 0,5.522 8.059,10 18,10 C -8.059,10 0,5.522 0,0" id="path26" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g28" transform="translate(19,6)"> <path d="m 0,0 c -14.958,0 -17,15 -17,19 l 34,0 C 17,17 15.042,0 0,0" id="path30" style="fill:#f5f8fa;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g32" transform="translate(32.8818,30.0483)"> <path d="M 0,0 C -1.357,0.938 -3.103,1.694 -5.121,2.25 -3.246,2.826 -0.57,2.559 0,0 M 2.503,-2.692 C 4.945,7.43 -7.278,5.014 -9.701,3.106 c -1.34,0.149 -2.736,0.234 -4.181,0.234 -9.389,0 -17,-3.228 -17,-8.444 0,-5.216 7.611,-9.444 17,-9.444 9.389,0 17,4.228 17,9.444 0,0.862 -0.225,1.664 -0.615,2.412" id="path34" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> </g> </g> <g id="g36"> <g clip-path="url(#clipPath40)" id="g38"> <g id="g44" transform="translate(34,24)"> <path d="m 0,0 c 0,-3.866 -6.716,-7 -15,-7 -8.284,0 -15,3.134 -15,7 0,3.866 6.716,7 15,7 C -6.716,7 0,3.866 0,0" id="path46" style="fill:#8a4b38;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g48" transform="translate(21,20)"> <path d="m 0,0 c -0.256,0 -0.512,0.098 -0.707,0.293 -2.337,2.337 -2.376,4.885 -0.125,8.262 0.739,1.109 0.9,2.245 0.478,3.377 -0.461,1.235 -1.438,1.996 -1.731,2.076 -0.553,0 -0.958,0.444 -0.958,0.996 C -3.043,15.557 -2.552,16 -2,16 -1.003,16 0.395,14.847 1.183,13.375 2.217,11.442 2.093,9.336 0.832,7.445 -1.129,4.503 -0.699,3.113 0.707,1.707 1.098,1.316 1.098,0.684 0.707,0.293 0.512,0.098 0.256,0 0,0" id="path50" style="fill:#d99e82;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g52" transform="translate(15,22)"> <path d="m 0,0 c -0.256,0 -0.512,0.098 -0.707,0.293 -2.337,2.337 -2.376,4.885 -0.125,8.262 0.727,1.091 0.894,2.082 0.494,2.947 -0.444,0.961 -1.431,1.469 -1.684,1.499 -0.552,0 -0.989,0.447 -0.989,0.999 0,0.553 0.459,1 1.011,1 0.997,0 2.584,-0.974 3.36,-2.423 C 1.841,11.678 2.413,9.816 0.832,7.445 -1.129,4.503 -0.699,3.113 0.707,1.707 1.098,1.316 1.098,0.684 0.707,0.293 0.512,0.098 0.256,0 0,0" id="path54" style="fill:#d99e82;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> </g> </g> </g> </g></svg>
|
<svg class="w-6 h-6 inline-block ml-2" viewBox="0 0 47.5 47.5" id="svg2" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" fill="#ffffff"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <defs id="defs6"> <clipPath clipPathUnits="userSpaceOnUse" id="clipPath16"> <path d="M 0,38 38,38 38,0 0,0 0,38 Z" id="path18"></path> </clipPath> <clipPath clipPathUnits="userSpaceOnUse" id="clipPath40"> <path d="M 0,38 38,38 38,0 0,0 0,38 Z" id="path42"></path> </clipPath> </defs> <g id="g10" transform="matrix(1.25,0,0,-1.25,0,47.5)"> <g id="g12"> <g clip-path="url(#clipPath16)" id="g14"> <g id="g20" transform="translate(37,11)"> <path d="m 0,0 c 0,-5.522 -8.059,-10 -18,-10 -9.941,0 -18,4.478 -18,10 0,5.522 8.059,10 18,10 C -8.059,10 0,5.522 0,0" id="path22" style="fill:#99aab5;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g24" transform="translate(37,13)"> <path d="m 0,0 c 0,-5.522 -8.059,-10 -18,-10 -9.941,0 -18,4.478 -18,10 0,5.522 8.059,10 18,10 C -8.059,10 0,5.522 0,0" id="path26" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g28" transform="translate(19,6)"> <path d="m 0,0 c -14.958,0 -17,15 -17,19 l 34,0 C 17,17 15.042,0 0,0" id="path30" style="fill:#f5f8fa;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g32" transform="translate(32.8818,30.0483)"> <path d="M 0,0 C -1.357,0.938 -3.103,1.694 -5.121,2.25 -3.246,2.826 -0.57,2.559 0,0 M 2.503,-2.692 C 4.945,7.43 -7.278,5.014 -9.701,3.106 c -1.34,0.149 -2.736,0.234 -4.181,0.234 -9.389,0 -17,-3.228 -17,-8.444 0,-5.216 7.611,-9.444 17,-9.444 9.389,0 17,4.228 17,9.444 0,0.862 -0.225,1.664 -0.615,2.412" id="path34" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> </g> </g> <g id="g36"> <g clip-path="url(#clipPath40)" id="g38"> <g id="g44" transform="translate(34,24)"> <path d="m 0,0 c 0,-3.866 -6.716,-7 -15,-7 -8.284,0 -15,3.134 -15,7 0,3.866 6.716,7 15,7 C -6.716,7 0,3.866 0,0" id="path46" style="fill:#8a4b38;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g48" transform="translate(21,20)"> <path d="m 0,0 c -0.256,0 -0.512,0.098 -0.707,0.293 -2.337,2.337 -2.376,4.885 -0.125,8.262 0.739,1.109 0.9,2.245 0.478,3.377 -0.461,1.235 -1.438,1.996 -1.731,2.076 -0.553,0 -0.958,0.444 -0.958,0.996 C -3.043,15.557 -2.552,16 -2,16 -1.003,16 0.395,14.847 1.183,13.375 2.217,11.442 2.093,9.336 0.832,7.445 -1.129,4.503 -0.699,3.113 0.707,1.707 1.098,1.316 1.098,0.684 0.707,0.293 0.512,0.098 0.256,0 0,0" id="path50" style="fill:#d99e82;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> <g id="g52" transform="translate(15,22)"> <path d="m 0,0 c -0.256,0 -0.512,0.098 -0.707,0.293 -2.337,2.337 -2.376,4.885 -0.125,8.262 0.727,1.091 0.894,2.082 0.494,2.947 -0.444,0.961 -1.431,1.469 -1.684,1.499 -0.552,0 -0.989,0.447 -0.989,0.999 0,0.553 0.459,1 1.011,1 0.997,0 2.584,-0.974 3.36,-2.423 C 1.841,11.678 2.413,9.816 0.832,7.445 -1.129,4.503 -0.699,3.113 0.707,1.707 1.098,1.316 1.098,0.684 0.707,0.293 0.512,0.098 0.256,0 0,0" id="path54" style="fill:#d99e82;fill-opacity:1;fill-rule:nonzero;stroke:none"></path> </g> </g> </g> </g> </g></svg>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user