1function membershipStore() { 2 return { 3 memberships: [], 4 loading: false, 5 limit: 8, 6 page: 0, 7 hasMore: true, 8 9 async init() { 10 await this.fetchData(); 11 this.setupScroll(); 12 }, 13 14 async fetchData() { 15 if (this.loading || !this.hasMore) return; 16 17 const currentOrg = getCurrentOrg(); 18 this.loading = true; 19 20 try { 21 const payload = { 22 sort: { field: "createdDate", order: "descend" }, 23 scroll: true, 24 p: this.page, 25 s: this.limit, 26 query: "", 27 filters: {}, 28 timeZone: "Asia/Calcutta", 29 }; 30 31 const res = await fetch(`/t/api/content/public/membership/get/all?orgId=${currentOrg._id}`, { 32 method: "POST", 33 headers: { 34 "Content-Type": "application/json", 35 }, 36 body: JSON.stringify(payload), 37 }); 38 39 const data = await res.json(); 40 const membershipList = data?.data || []; 41 const { hasMore, total } = data; 42 43 // Show dummy data if in preview mode and data is empty 44 const shouldShowMockMemberships = isPreviewMode?.() && total === 0; 45 if (shouldShowMockMemberships) { 46 this.memberships = getMockMemberships(); 47 this.hasMore = false; 48 this.loading = false; 49 this.page++; 50 return; 51 } 52 53 const newList = membershipList 54 .filter(hasPlansForThisCountry) 55 .map(m => m.unified ? normalizeUnifiedMembership(m) : normalizeMembership(m)) 56 57 this.memberships.push(...newList); 58 59 this.hasMore = hasMore; 60 this.page++; 61 this.loading = false; 62 } catch (error) { 63 console.error("Error fetching membership list:", error); 64 this.loading = false; 65 } 66 }, 67 68 setupScroll() { 69 window.addEventListener("scroll", () => { 70 const nearBottom = 71 window.innerHeight + window.scrollY >= document.body.offsetHeight - 200; 72 73 if (nearBottom) { 74 this.fetchData(); 75 } 76 }); 77 } 78 }; 79} 80 81function normalizeMembership(membership) { 82 const subscriptions = membership?.subscriptions ?? []; 83 const curreny = membership?.currency ?? "INR"; 84 85 const recommendedPlan = subscriptions?.find(sub => sub.subscriptionRecurPeriod === membership?.recommendedPlan) 86 const { subscriptionAmount, subscriptionDiscountedAmount, subscriptionDiscount, subscriptionRecurPeriod } = recommendedPlan ?? {}; 87 88 const PLAN_ID_MAP = { 89 yearly: "p1", 90 quarterly: "p2", 91 monthly: "p3", 92 }; 93 94 const getPaymentLabel = (amount, period) => { 95 return `Subscription plan`; 96 }; 97 98 const getValidityLabel = (period) => { 99 if (period === "yearly") return "12 months"; 100 if (period === "quarterly") return "/ 3 months"; 101 if (period === "monthly") return "/ 1 month"; 102 103 return "/ 12 months"; 104 }; 105 106 return { 107 id: `legacy-membership`, 108 title: membership?.title, 109 coverImage: membership?.coverUrl || membership?.coverImageUrl || membership?.thumbnail, 110 paymentLabel: getPaymentLabel(subscriptionDiscountedAmount, subscriptionRecurPeriod), 111 priceLabel: getAmountWithCurrency(subscriptionDiscountedAmount, curreny), 112 mrpLabel: subscriptionDiscount > 0 ? getAmountWithCurrency(subscriptionAmount, curreny) : null, 113 validityLabel: getValidityLabel(subscriptionRecurPeriod), 114 membershipUrl: `/membership` 115 } 116} 117 118function normalizeUnifiedMembership(membership) { 119 const { resolvedPlans, resolvedCurrency } = getResolvedCurrencyAndPlans(membership); 120 const defaultPlan = resolvedPlans?.filter(plan => plan.status === "ACTIVE")?.find(plan => plan.isDefault); 121 const { price = 0, mrp = 0, type }
121 = defaultPlan ?? {}; 122 123 const getPaymentLabel = (type) => { 124 if (type === 'OTP') return "One time purchase"; 125 if (type === 'FREE') return "Free plan"; 126 if (type === 'SUBSCRIPTION') return "Subscription plan"; 127 return "One time payment"; 128 } 129 130 const getValidityLabel = (validity) => { 131 const { type, duration } = validity; 132 if (type === 'UNLIMITED') return "/ Lifetime"; 133 if (type === 'DURATION') { 134 if (duration?.endDate) return `Valid till ${new Date(duration.endDate).toLocaleDateString()}`; 135 return `/ ${duration.value} ${duration?.unit?.toLowerCase()}`; 136 } 137 } 138 139 return { 140 id: membership.id, 141 title: membership.title, 142 coverImage: membership?.coverUrl || membership?.coverImageUrl || membership?.thumbnail, 143 paymentLabel: getPaymentLabel(type), 144 priceLabel: getAmountWithCurrency(price, resolvedCurrency), 145 mrpLabel: mrp && mrp > price ? getAmountWithCurrency(mrp, resolvedCurrency) : null, 146 validityLabel: getValidityLabel(defaultPlan?.validity), 147 membershipUrl: `/memberships/${membership.id}` 148 } 149} 150 151function getMockMemberships() { 152 const mockMemberships = getMockProducts()?.memberships || [] 153 154 // Just to visually align with previous mock function logic 155 return mockMemberships.map((membership, idx) => ({ 156 id: `mock-membership-${idx + 1}`, 157 title: membership.title, 158 coverImage: membership.image_url || getCdnUrl() + membership.image_path, 159 paymentLabel: "Subscription plan", 160 priceLabel: getAmountWithCurrency(membership.price, "INR"), 161 mrpLabel: membership.mrp > membership.price ? getAmountWithCurrency(membership.mrp, "INR") : null, 162 validityLabel: "12 months", 163 membershipUrl: "javascript:void(0)", 164 })); 165}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.