feature: change from monthly to annual plan

This commit is contained in:
MuslemRahimi 2024-06-17 09:43:32 +02:00
parent 49dc765254
commit de82cf813f
3 changed files with 139 additions and 30 deletions

View File

@ -34,8 +34,6 @@ export const actions = {
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 = {
@ -49,8 +47,6 @@ export const actions = {
headers: headers
});
} catch (err) {
console.log("Error: ", err);
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');
},
};

View File

@ -15,7 +15,6 @@
import { pb } from '$lib/pocketbase';
import { z } from 'zod';
import { updatePersonalDataSchema, updatePasswordSchema} from '$lib/schemas';
import communityBanner from '$lib/images/community_banner.jpg';
import { enhance } from '$app/forms';
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
const response = await fetch('/api/reactivate-subscription', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const output = await response.json();
setTimeout(() => {
if (result.type === 'redirect') {
const anchor = document.createElement('a');
anchor.href = '/community/profile';
anchor.dataset.sveltekitReload = true;
document.body.appendChild(anchor);
anchor.dispatchEvent(new MouseEvent('click'));
}
}, 5000);
}
}
async function updateAvatar(event)
{
@ -446,7 +472,7 @@ async function getPost() {
let showTab = 'post';
let showTab = 'subscription';
let settingsTab = 'personalData';
@ -897,9 +923,18 @@ onDestroy(async () => {
</div>
{#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">
Cancel Subscription
</label>
<div class="flex flex-col items-start sm:flex-row sm:items-center">
<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">
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'}
<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
@ -1061,3 +1096,41 @@ onDestroy(async () => {
</dialog>
<!-- 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 -->

View File

@ -128,7 +128,7 @@ async function purchasePlan() {
Pay Yearly
</span>
<span class="text-[#10DB06] text-sm font-bold text-opacity-[0.8]">
Save up 25%
Save up 22%
</span>
</div>
@ -250,16 +250,11 @@ async function purchasePlan() {
<div class="flex flex-col mb-6 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="text-white text-xl">/month</span>
<span class="mr-2 text-4xl font-bold">{mode ? '$499' : '$49.99'}</span>
<span class="text-white text-xl">{mode ? '/year' : '/month'}</span>
</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">
only ${mode ? (7.5/4)?.toFixed(2) : (9.99/4)?.toFixed(2)} / week, less than a
{#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>
{/if}
</div>
-->
</div>