ultimate-jekyll-manager 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -1
- package/_notes/NOTES-app.md +92 -0
- package/_notes/NOTES-sub-2.md +42 -0
- package/_notes/NOTES-sub-ai.md +165 -0
- package/_notes/NOTES-sub-endpoints.md +44 -0
- package/_notes/NOTES-sub-example.md +92 -0
- package/_notes/NOTES-sub-plan.md +36 -0
- package/_notes/NOTES-sub-status.md +123 -0
- package/_notes/TODO-frontend.md +61 -0
- package/assets/logos/brandmarks/original/apple-app-store.svg +1 -0
- package/assets/logos/brandmarks/original/apple.svg +1 -0
- package/assets/logos/brandmarks/original/bitcoin.svg +1 -0
- package/assets/logos/brandmarks/original/bootstrap.svg +43 -0
- package/assets/logos/brandmarks/original/discord.svg +1 -0
- package/assets/logos/brandmarks/original/facebook-f.svg +1 -0
- package/assets/logos/brandmarks/original/facebook.svg +1 -0
- package/assets/logos/brandmarks/original/github.svg +6 -0
- package/assets/logos/brandmarks/original/gitlab.svg +17 -0
- package/assets/logos/brandmarks/original/google-a-s.svg +1 -0
- package/assets/logos/brandmarks/original/google-chrome-webstore.svg +49 -0
- package/assets/logos/brandmarks/original/google-play-store.svg +1 -0
- package/assets/logos/brandmarks/original/google-web-search.svg +1 -0
- package/assets/logos/brandmarks/original/google.svg +1 -0
- package/assets/logos/brandmarks/original/gulp.svg +4 -0
- package/assets/logos/brandmarks/original/html-5.svg +1 -0
- package/assets/logos/brandmarks/original/instagram.svg +1 -0
- package/assets/logos/brandmarks/original/javascript.svg +1 -0
- package/assets/logos/brandmarks/original/jira.svg +23 -0
- package/assets/logos/brandmarks/original/linkedin.svg +1 -0
- package/assets/logos/brandmarks/original/linux.svg +28 -0
- package/assets/logos/brandmarks/original/microsoft.svg +1 -0
- package/assets/logos/brandmarks/original/npm.svg +8 -0
- package/assets/logos/brandmarks/original/pinterest.svg +1 -0
- package/assets/logos/brandmarks/original/reddit.svg +1 -0
- package/assets/logos/brandmarks/original/sass.svg +3 -0
- package/assets/logos/brandmarks/original/slack.svg +33 -0
- package/assets/logos/brandmarks/original/soundcloud.svg +1 -0
- package/assets/logos/brandmarks/original/spotify.svg +5 -0
- package/assets/logos/brandmarks/original/tiktok.svg +1 -0
- package/assets/logos/brandmarks/original/tumblr.svg +1 -0
- package/assets/logos/brandmarks/original/twitter.svg +1 -0
- package/assets/logos/brandmarks/original/yahoo-y.svg +1 -0
- package/assets/logos/brandmarks/original/youtube-square.svg +1 -0
- package/assets/logos/brandmarks/original/youtube.svg +1 -0
- package/assets/logos/combomarks/dark/airbnb.svg +30 -0
- package/assets/logos/combomarks/dark/slack.svg +38 -0
- package/assets/logos/combomarks/dark/spotify.svg +35 -0
- package/assets/logos/combomarks/dark/twilio.svg +26 -0
- package/assets/logos/combomarks/dark/weebly.svg +35 -0
- package/assets/logos/combomarks/gray/airbnb.svg +33 -0
- package/assets/logos/combomarks/gray/alphabet.svg +23 -0
- package/assets/logos/combomarks/gray/amazon.svg +38 -0
- package/assets/logos/combomarks/gray/boring-company.svg +91 -0
- package/assets/logos/combomarks/gray/burberry.svg +239 -0
- package/assets/logos/combomarks/gray/embark.svg +21 -0
- package/assets/logos/combomarks/gray/fitbit.svg +61 -0
- package/assets/logos/combomarks/gray/fred-perry.svg +94 -0
- package/assets/logos/combomarks/gray/google.svg +27 -0
- package/assets/logos/combomarks/gray/hollister.svg +34 -0
- package/assets/logos/combomarks/gray/hubspot.svg +27 -0
- package/assets/logos/combomarks/gray/kaplan.svg +33 -0
- package/assets/logos/combomarks/gray/lenovo.svg +27 -0
- package/assets/logos/combomarks/gray/levis.svg +25 -0
- package/assets/logos/combomarks/gray/mapbox.svg +37 -0
- package/assets/logos/combomarks/gray/netflix.svg +15 -0
- package/assets/logos/combomarks/gray/new-balance.svg +32 -0
- package/assets/logos/combomarks/gray/nike.svg +17 -0
- package/assets/logos/combomarks/gray/paypal.svg +41 -0
- package/assets/logos/combomarks/gray/puma.svg +82 -0
- package/assets/logos/combomarks/gray/samsung.svg +26 -0
- package/assets/logos/combomarks/gray/shopify.svg +36 -0
- package/assets/logos/combomarks/gray/slack.svg +42 -0
- package/assets/logos/combomarks/gray/spotify.svg +38 -0
- package/assets/logos/combomarks/gray/stripe.svg +24 -0
- package/assets/logos/combomarks/gray/tnf.svg +30 -0
- package/assets/logos/combomarks/gray/twilio.svg +29 -0
- package/assets/logos/combomarks/gray/uber.svg +24 -0
- package/assets/logos/combomarks/gray/weebly.svg +38 -0
- package/assets/logos/combomarks/original/airbnb.svg +33 -0
- package/assets/logos/combomarks/original/alphabet.svg +23 -0
- package/assets/logos/combomarks/original/amazon.svg +38 -0
- package/assets/logos/combomarks/original/boring-company.svg +91 -0
- package/assets/logos/combomarks/original/embark.svg +24 -0
- package/assets/logos/combomarks/original/fitbit.svg +60 -0
- package/assets/logos/combomarks/original/google.svg +28 -0
- package/assets/logos/combomarks/original/hubspot.svg +29 -0
- package/assets/logos/combomarks/original/lenovo.svg +24 -0
- package/assets/logos/combomarks/original/mapbox.svg +39 -0
- package/assets/logos/combomarks/original/netflix.svg +15 -0
- package/assets/logos/combomarks/original/paypal.svg +41 -0
- package/assets/logos/combomarks/original/samsung.svg +25 -0
- package/assets/logos/combomarks/original/shopify.svg +35 -0
- package/assets/logos/combomarks/original/slack.svg +47 -0
- package/assets/logos/combomarks/original/spotify.svg +37 -0
- package/assets/logos/combomarks/original/stripe.svg +24 -0
- package/assets/logos/combomarks/original/uber.svg +24 -0
- package/assets/logos/combomarks/original/weebly.svg +34 -0
- package/assets/logos/combomarks/white/airbnb.svg +33 -0
- package/assets/logos/combomarks/white/alphabet.svg +23 -0
- package/assets/logos/combomarks/white/amazon.svg +38 -0
- package/assets/logos/combomarks/white/boring-company.svg +91 -0
- package/assets/logos/combomarks/white/embark.svg +21 -0
- package/assets/logos/combomarks/white/fitbit.svg +61 -0
- package/assets/logos/combomarks/white/google.svg +27 -0
- package/assets/logos/combomarks/white/hubspot.svg +27 -0
- package/assets/logos/combomarks/white/kaplan.svg +33 -0
- package/assets/logos/combomarks/white/lenovo.svg +27 -0
- package/assets/logos/combomarks/white/mapbox.svg +37 -0
- package/assets/logos/combomarks/white/netflix.svg +15 -0
- package/assets/logos/combomarks/white/paypal.svg +40 -0
- package/assets/logos/combomarks/white/samsung.svg +26 -0
- package/assets/logos/combomarks/white/shopify.svg +36 -0
- package/assets/logos/combomarks/white/slack.svg +42 -0
- package/assets/logos/combomarks/white/spotify.svg +38 -0
- package/assets/logos/combomarks/white/stripe.svg +24 -0
- package/assets/logos/combomarks/white/twilio.svg +29 -0
- package/assets/logos/combomarks/white/uber.svg +24 -0
- package/assets/logos/combomarks/white/weebly.svg +38 -0
- package/dist/assets/css/core/alert.scss +32 -16
- package/dist/assets/css/core/animations.scss +212 -188
- package/dist/assets/css/core/buttons.scss +22 -23
- package/dist/assets/css/core/chatsy.scss +36 -21
- package/dist/assets/css/core/cookieconsent.scss +49 -74
- package/dist/assets/css/core/custom-font-awesome.scss +21 -9
- package/dist/assets/css/core/initialize.scss +16 -5
- package/dist/assets/css/core/lazy-loading.scss +25 -31
- package/dist/assets/css/core/social-sharing.scss +7 -2
- package/dist/assets/css/core/utilities.scss +39 -16
- package/dist/assets/css/pages/download/index.scss +250 -0
- package/dist/assets/css/pages/payment/confirmation/index.scss +1 -51
- package/dist/assets/css/ultimate-jekyll-manager.scss +0 -3
- package/dist/assets/js/core/chatsy.js +5 -5
- package/dist/assets/js/core/lazy-loading.js +72 -12
- package/dist/assets/js/core/page-loader.js +3 -1
- package/dist/assets/js/core/query-strings.js +4 -2
- package/dist/assets/js/libs/dev.js +25 -25
- package/dist/assets/js/modules/vert.js +283 -0
- package/dist/assets/js/pages/account/sections/api-keys.js +5 -3
- package/dist/assets/js/pages/account/sections/billing.js +36 -42
- package/dist/assets/js/pages/account/sections/profile.js +5 -3
- package/dist/assets/js/pages/account/sections/referrals.js +5 -3
- package/dist/assets/js/pages/blog/post.js +114 -0
- package/dist/assets/js/pages/download/index.js +352 -0
- package/dist/assets/js/pages/payment/checkout/modules/session.js +19 -10
- package/dist/assets/js/pages/payment/checkout/modules/ui.js +8 -8
- package/dist/assets/js/pages/pricing/index.js +83 -0
- package/dist/assets/js/ultimate-jekyll-manager.js +3 -0
- package/dist/assets/themes/bootstrap/_theme.scss +3 -3
- package/dist/assets/themes/classy/_theme.js +7 -1
- package/dist/assets/themes/classy/_theme.scss +23 -15
- package/dist/assets/themes/classy/css/base/_backgrounds.scss +105 -0
- package/dist/assets/themes/classy/css/base/_borders.scss +56 -0
- package/dist/assets/themes/classy/css/{_soft-colors.scss → base/_soft-colors.scss} +12 -4
- package/dist/assets/themes/classy/css/{_spacing.scss → base/_spacing.scss} +14 -2
- package/dist/assets/themes/classy/css/{_typography.scss → base/_typography.scss} +55 -17
- package/dist/assets/themes/classy/css/base/_utilities.scss +77 -0
- package/dist/assets/themes/classy/css/{_variables.scss → base/_variables.scss} +32 -9
- package/dist/assets/themes/classy/css/{_avatars.scss → components/_avatars.scss} +15 -5
- package/dist/assets/themes/classy/css/components/_badges.scss +25 -0
- package/dist/assets/themes/classy/css/{_buttons.scss → components/_buttons.scss} +82 -149
- package/dist/assets/themes/classy/css/components/_cards.scss +33 -0
- package/dist/assets/themes/classy/css/{_forms.scss → components/_forms.scss} +12 -4
- package/dist/assets/themes/classy/css/{_links.scss → components/_links.scss} +6 -1
- package/dist/assets/themes/classy/css/components/_logo-scroll.scss +57 -0
- package/dist/assets/themes/classy/css/components/_spinners.scss +19 -0
- package/dist/assets/themes/classy/css/layout/_blog.scss +42 -0
- package/dist/assets/themes/classy/css/layout/_general.scss +43 -0
- package/dist/assets/themes/classy/css/{_navigation.scss → layout/_navigation.scss} +39 -45
- package/dist/assets/themes/classy/css/layout/_team.scss +18 -0
- package/dist/assets/themes/classy/js/logo-scroll.js +83 -0
- package/dist/assets/themes/classy/js/navbar-scroll.js +48 -13
- package/dist/defaults/dist/_includes/core/foot.html +3 -0
- package/dist/defaults/dist/_includes/modules/adunits/adsense.html +57 -60
- package/dist/defaults/dist/_includes/themes/classy/backend/sections/nav.html +1 -1
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +23 -21
- package/dist/defaults/dist/_layouts/blueprint/about.html +12 -0
- package/dist/defaults/dist/_layouts/blueprint/download.html +12 -0
- package/dist/defaults/dist/_layouts/core/root.html +3 -1
- package/dist/defaults/dist/_layouts/modules/utilities/redirect.html +8 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/core/base.html +36 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/core/minimal.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/404.html +8 -33
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +265 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +636 -688
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/oauth2.html +15 -15
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +8 -17
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +26 -15
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +21 -12
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +132 -114
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +75 -57
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +51 -47
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +748 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +289 -141
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +14 -14
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/confirmation.html +28 -19
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +226 -83
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/index.html +127 -190
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/member.html +162 -1
- package/dist/defaults/dist/_team/alex.md +3 -1
- package/dist/defaults/dist/_team/ian.md +5 -1
- package/dist/defaults/dist/ads.txt +1 -1
- package/dist/defaults/dist/pages/about.md +7 -0
- package/dist/defaults/dist/pages/team/index.md +7 -0
- package/dist/defaults/dist/pages/test/libraries/adsense.html +68 -0
- package/dist/defaults/dist/pages/test/libraries/bootstrap-components.html +136 -93
- package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +47 -29
- package/dist/defaults/dist/redirects/authentication/helpers/forgot.html +9 -0
- package/dist/defaults/dist/redirects/download/{linux-debian.html → helpers/linux-debian.html} +1 -1
- package/dist/defaults/dist/redirects/download/{linux-snap.html → helpers/linux-snap.html} +1 -1
- package/dist/defaults/dist/redirects/download/linux/debian.html +9 -0
- package/dist/defaults/dist/redirects/download/linux/index.html +9 -0
- package/dist/defaults/dist/redirects/download/linux/snap.html +9 -0
- package/dist/defaults/dist/redirects/download/{mac.html → mac/index.html} +1 -1
- package/dist/defaults/dist/redirects/download/mac/universal.html +9 -0
- package/dist/defaults/dist/redirects/download/{windows.html → windows/index.html} +1 -1
- package/dist/defaults/dist/redirects/download/windows/universal.html +9 -0
- package/dist/defaults/src/_config.yml +11 -6
- package/dist/defaults/src/_includes/frontend/sections/footer.json +64 -3
- package/dist/defaults/src/_includes/frontend/sections/nav.json +61 -27
- package/dist/gulp/tasks/distribute.js +3 -0
- package/dist/gulp/tasks/sass.js +14 -13
- package/dist/gulp/tasks/webpack.js +15 -0
- package/dist/index.js +13 -3
- package/dist/service-worker.js +65 -24
- package/package.json +4 -4
- package/dist/assets/css/core/temp-custom.scss +0 -2
- package/dist/assets/themes/classy/css/_badges.scss +0 -170
- package/dist/assets/themes/classy/css/_blog.scss +0 -35
- package/dist/assets/themes/classy/css/_cards.scss +0 -387
- package/dist/assets/themes/classy/css/_utilities.scss +0 -397
- package/dist/defaults/dist/_includes/modules/adunits/fallback.html +0 -164
- package/dist/defaults/dist/_layouts/blueprint/about.md +0 -48
- package/dist/defaults/dist/_layouts/blueprint/download.md +0 -49
- /package/{CLAUDE-pages.md → _notes/CLAUDE-pages.md} +0 -0
- /package/{CLAUDE-pages2.md → _notes/CLAUDE-pages2.md} +0 -0
- /package/{TODO-Claude.rtf → _notes/TODO-Claude.rtf} +0 -0
- /package/{TODO-FileStructure.md → _notes/TODO-FileStructure.md} +0 -0
- /package/{TODO-checkout.md → _notes/TODO-checkout.md} +0 -0
- /package/{TODO-legacy.md → _notes/TODO-legacy.md} +0 -0
- /package/{TODO-template-system.md → _notes/TODO-template-system.md} +0 -0
- /package/{TODO-theme.md → _notes/TODO-theme.md} +0 -0
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
"Read(/Users/ian/Developer/Repositories/ITW-Creative-Works/jekyll-uj-powertools/**)",
|
|
35
35
|
"Read(/Users/ian/Developer/Repositories/ITW-Creative-Works/jekyll-uj-powertools/**)",
|
|
36
36
|
"Read(/Users/ian/Developer/Repositories/ITW-Creative-Works/jekyll-uj-powertools/**)",
|
|
37
|
-
"Read(/Users/ian/Developer/Repositories/ITW-Creative-Works/jekyll-uj-powertools/**)"
|
|
37
|
+
"Read(/Users/ian/Developer/Repositories/ITW-Creative-Works/jekyll-uj-powertools/**)",
|
|
38
|
+
"Bash(for:*)",
|
|
39
|
+
"Bash(do if [[ \"$file\" != *\"-\"* ]])",
|
|
40
|
+
"Bash(then [ -f \"$file\" ])",
|
|
41
|
+
"Bash(fi)",
|
|
42
|
+
"Bash(done)",
|
|
43
|
+
"Bash(do [ -f \"$file\" ])"
|
|
38
44
|
],
|
|
39
45
|
"deny": []
|
|
40
46
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": "https://us-central1-studymonkey-ai.cloudfunctions.net",
|
|
3
|
+
"images": {
|
|
4
|
+
"combomark": "https://cdn.itwcreativeworks.com/assets/studymonkey/images/logo/studymonkey-combomark-black-1024x.png",
|
|
5
|
+
"brandmark": "https://cdn.itwcreativeworks.com/assets/studymonkey/images/logo/studymonkey-brandmark-black-1024x1024.png",
|
|
6
|
+
"wordmark": "https://cdn.itwcreativeworks.com/assets/studymonkey/images/logo/studymonkey-wordmark-black-1024x.png"
|
|
7
|
+
},
|
|
8
|
+
"github": {
|
|
9
|
+
"repo": "studymonkey-website",
|
|
10
|
+
"user": "ianwieds"
|
|
11
|
+
},
|
|
12
|
+
"apiKeys": {
|
|
13
|
+
"stripe": {
|
|
14
|
+
"publishableKey": "pk_live_51Mirn8HGybgi7uQGuE5IcaED0VByYRfVXGUmBDqnUyldcf2BJrpiFCDmwu4NoSDv34LMBw5mfCNdB3pmRki0jhmx00jFgW4akz"
|
|
15
|
+
},
|
|
16
|
+
"chatsy": {
|
|
17
|
+
"accountId": "EG6j4wzyykSrHluANgIVTvyjzyu1",
|
|
18
|
+
"chatId": "LP8IKB0sRjARSO"
|
|
19
|
+
},
|
|
20
|
+
"paypal": {
|
|
21
|
+
"clientId": "AQSXMAqVuJYriyKEpaEc9xhS4hkm7iSlLjNRXSBdkM234figh599SMQbc0VMfYrm2Vh74J3u4jdeFYH9"
|
|
22
|
+
},
|
|
23
|
+
"chargebee": {
|
|
24
|
+
"siteKey": ""
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"oauth2": {
|
|
28
|
+
"discord": {
|
|
29
|
+
"scope": ["identify", "guilds", "guilds.join"],
|
|
30
|
+
"enabled": true
|
|
31
|
+
},
|
|
32
|
+
"google": {
|
|
33
|
+
"enabled": false
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"url": "https://studymonkey.ai",
|
|
37
|
+
"products": {
|
|
38
|
+
"studymonkey-homework-helper": {
|
|
39
|
+
"successURLText": "Start Studying!",
|
|
40
|
+
"name": "StudyMonkey Homework Helper",
|
|
41
|
+
"monthly": {
|
|
42
|
+
"stripeProductId": "prod_NTqQASoK03O5fP",
|
|
43
|
+
"price": 8,
|
|
44
|
+
"chargebeePlanId": "",
|
|
45
|
+
"paypalPlanId": "plan.id",
|
|
46
|
+
"stripePriceId": "price_1MisjzHGybgi7uQGw5MH7VZx"
|
|
47
|
+
},
|
|
48
|
+
"successURL": "https://studymonkey.ai/dashboard",
|
|
49
|
+
"planId": "homework-helper",
|
|
50
|
+
"spreadsheetId": "1d0elQATs7mpur6IwlyWy_7s2vWvUZYT0nfF2WtTiKjQ",
|
|
51
|
+
"type": "subscription",
|
|
52
|
+
"limits": {
|
|
53
|
+
"devices": 3,
|
|
54
|
+
"requests": 50
|
|
55
|
+
},
|
|
56
|
+
"trial": 14,
|
|
57
|
+
"annually": {
|
|
58
|
+
"stripeProductId": "prod_NTqYLkXCOhAwa5",
|
|
59
|
+
"price": 72,
|
|
60
|
+
"chargebeePlanId": "",
|
|
61
|
+
"paypalPlanId": "plan.id",
|
|
62
|
+
"stripePriceId": "price_1MisrnHGybgi7uQGn0XOVjRo"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"reviews": {
|
|
67
|
+
"sites": ["https://www.trustpilot.com/review/studymonkey.ai"]
|
|
68
|
+
},
|
|
69
|
+
"name": "StudyMonkey",
|
|
70
|
+
"id": "studymonkey",
|
|
71
|
+
"brand": {
|
|
72
|
+
"description": "StudyMonkey is an AI-powered tutor that helps you with your homework and studying."
|
|
73
|
+
},
|
|
74
|
+
"dashboard": true,
|
|
75
|
+
"email": "support@studymonkey.ai",
|
|
76
|
+
"sponsorships": {
|
|
77
|
+
"acceptable": ["education", "academic"],
|
|
78
|
+
"unacceptable": ["online homework services", "essay writing service", "online writing services"],
|
|
79
|
+
"prices": {
|
|
80
|
+
"guest-post": 40,
|
|
81
|
+
"link-insertion": 30
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"authentication": {
|
|
85
|
+
"password": {
|
|
86
|
+
"enabled": true
|
|
87
|
+
},
|
|
88
|
+
"google.com": {
|
|
89
|
+
"enabled": true
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Flags for special conditions
|
|
2
|
+
flags: {
|
|
3
|
+
hasDispute: false,
|
|
4
|
+
hasRefund: false,
|
|
5
|
+
isDelinquent: false,
|
|
6
|
+
requiresAction: false,
|
|
7
|
+
autoRenewEnabled: true,
|
|
8
|
+
cancellationRequested: false,
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
// Dispute information (if applicable)
|
|
12
|
+
dispute: {
|
|
13
|
+
active: false,
|
|
14
|
+
createdAt: timestamp,
|
|
15
|
+
amount: 99.99,
|
|
16
|
+
reason: "fraudulent",
|
|
17
|
+
status: "warning_needs_response",
|
|
18
|
+
dueBy: timestamp,
|
|
19
|
+
evidence: {
|
|
20
|
+
submitted: false,
|
|
21
|
+
documents: []
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// Refund information (if applicable)
|
|
26
|
+
refunds: [
|
|
27
|
+
{
|
|
28
|
+
id: "refund-xxx",
|
|
29
|
+
amount: 99.99,
|
|
30
|
+
reason: "customer_request",
|
|
31
|
+
createdAt: timestamp,
|
|
32
|
+
metadata: {}
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
|
|
36
|
+
// Cancellation details (if cancelled)
|
|
37
|
+
cancellation: {
|
|
38
|
+
requestedAt: timestamp,
|
|
39
|
+
effectiveAt: timestamp, // When it actually ends
|
|
40
|
+
reason: "too_expensive",
|
|
41
|
+
feedback: "Price increased too much",
|
|
42
|
+
},
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
⏺ I'll help you design a comprehensive storage architecture for your payment system. Let me create a detailed plan
|
|
2
|
+
using the TodoWrite tool to track our implementation.
|
|
3
|
+
|
|
4
|
+
⏺ Update Todos
|
|
5
|
+
⎿ ☐ Design Firestore collections structure for payment system
|
|
6
|
+
☐ Implement active subscription checking before payment intent
|
|
7
|
+
☐ Enhance trial eligibility to check both UID and IP address
|
|
8
|
+
☐ Create abandoned cart tracking system
|
|
9
|
+
☐ Design unified subscription object structure
|
|
10
|
+
☐ Create webhook endpoints for Stripe, PayPal, Chargebee
|
|
11
|
+
☐ Implement app notification system for subscription events
|
|
12
|
+
|
|
13
|
+
⏺ Recommended Firestore Collections Structure
|
|
14
|
+
|
|
15
|
+
Based on your requirements, I recommend using multiple collections for better scalability and query efficiency:
|
|
16
|
+
|
|
17
|
+
1. payment-intents (Abandoned Cart Tracking)
|
|
18
|
+
|
|
19
|
+
{
|
|
20
|
+
id: "CHK-xxx", // checkout session ID
|
|
21
|
+
app: "app-id",
|
|
22
|
+
productId: "product-id",
|
|
23
|
+
userId: "uid", // optional, may be guest
|
|
24
|
+
email: "email@example.com",
|
|
25
|
+
ipAddress: "192.168.1.1",
|
|
26
|
+
status: "pending" | "completed" | "abandoned",
|
|
27
|
+
createdAt: timestamp,
|
|
28
|
+
updatedAt: timestamp,
|
|
29
|
+
lastVisitedAt: timestamp,
|
|
30
|
+
abandonedEmailsSent: {
|
|
31
|
+
day1: false,
|
|
32
|
+
day3: false,
|
|
33
|
+
day7: false
|
|
34
|
+
},
|
|
35
|
+
cartData: {
|
|
36
|
+
total: 99.99,
|
|
37
|
+
frequency: "monthly",
|
|
38
|
+
discount: "CODE20"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
2. payment-trials (Trial Eligibility)
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
id: auto,
|
|
46
|
+
app: "app-id",
|
|
47
|
+
productId: "product-id",
|
|
48
|
+
uid: "user-id",
|
|
49
|
+
ipAddress: "192.168.1.1",
|
|
50
|
+
startedAt: timestamp,
|
|
51
|
+
endedAt: timestamp,
|
|
52
|
+
trialDays: 7
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
3. payment-subscriptions (Unified Subscription Records)
|
|
56
|
+
|
|
57
|
+
{
|
|
58
|
+
id: "sub-xxx",
|
|
59
|
+
app: "app-id",
|
|
60
|
+
productId: "product-id",
|
|
61
|
+
userId: "uid",
|
|
62
|
+
email: "email@example.com",
|
|
63
|
+
processor: "stripe" | "paypal" | "chargebee",
|
|
64
|
+
processorSubscriptionId: "stripe_sub_xxx",
|
|
65
|
+
status: "active" | "cancelled" | "suspended" | "expired",
|
|
66
|
+
frequency: "monthly" | "annually",
|
|
67
|
+
amount: 99.99,
|
|
68
|
+
currency: "USD",
|
|
69
|
+
trialEnd: timestamp, // optional
|
|
70
|
+
currentPeriodStart: timestamp,
|
|
71
|
+
currentPeriodEnd: timestamp,
|
|
72
|
+
cancelledAt: timestamp, // optional
|
|
73
|
+
cancelReason: "string", // optional
|
|
74
|
+
createdAt: timestamp,
|
|
75
|
+
updatedAt: timestamp,
|
|
76
|
+
metadata: {
|
|
77
|
+
checkoutSessionId: "CHK-xxx",
|
|
78
|
+
webhookEvents: ["created", "updated", "cancelled"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
4. payment-orders (One-time Payments)
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
id: "order-xxx",
|
|
86
|
+
app: "app-id",
|
|
87
|
+
productId: "product-id",
|
|
88
|
+
userId: "uid",
|
|
89
|
+
email: "email@example.com",
|
|
90
|
+
processor: "stripe" | "paypal" | "chargebee",
|
|
91
|
+
processorOrderId: "stripe_pi_xxx",
|
|
92
|
+
status: "pending" | "completed" | "failed" | "refunded",
|
|
93
|
+
amount: 299.99,
|
|
94
|
+
currency: "USD",
|
|
95
|
+
createdAt: timestamp,
|
|
96
|
+
completedAt: timestamp,
|
|
97
|
+
metadata: {
|
|
98
|
+
checkoutSessionId: "CHK-xxx"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Implementation Flow
|
|
103
|
+
|
|
104
|
+
1. On Checkout Page Load (Client)
|
|
105
|
+
|
|
106
|
+
- Generate/retrieve checkout session ID
|
|
107
|
+
- Send cart data to /payment-v2/cart endpoint
|
|
108
|
+
- This creates/updates payment-intents document
|
|
109
|
+
|
|
110
|
+
2. Before Creating Payment Intent (/payment-v2/intent)
|
|
111
|
+
|
|
112
|
+
Check these in parallel:
|
|
113
|
+
- Active subscription check: Query payment-subscriptions where userId == uid && productId == productId && status
|
|
114
|
+
== 'active'
|
|
115
|
+
- Trial eligibility: Query payment-trials where (uid == userId || ipAddress == ip) && productId == productId &&
|
|
116
|
+
app == appId
|
|
117
|
+
- ReCAPTCHA verification: Already implemented
|
|
118
|
+
|
|
119
|
+
3. After Successful Payment Intent
|
|
120
|
+
|
|
121
|
+
- Update payment-intents with processor response data
|
|
122
|
+
- Store intent as "pending" until webhook confirmation
|
|
123
|
+
|
|
124
|
+
4. Webhook Processing (/payment-v2/webhook/[processor])
|
|
125
|
+
|
|
126
|
+
- Verify webhook signature
|
|
127
|
+
- Map processor event to unified status
|
|
128
|
+
- Update/create payment-subscriptions or payment-orders
|
|
129
|
+
- Update payment-intents status to "completed"
|
|
130
|
+
- Send notification to app's webhook endpoint
|
|
131
|
+
|
|
132
|
+
5. Abandoned Cart Cron Job
|
|
133
|
+
|
|
134
|
+
- Query payment-intents where status == 'pending'
|
|
135
|
+
- Check age and send appropriate emails
|
|
136
|
+
- Update abandonedEmailsSent flags
|
|
137
|
+
|
|
138
|
+
Endpoints Structure
|
|
139
|
+
|
|
140
|
+
/payment-v2/
|
|
141
|
+
├── cart/ # Track abandoned carts
|
|
142
|
+
├── intent/ # Create payment intent (existing)
|
|
143
|
+
├── webhook/
|
|
144
|
+
│ ├── stripe/
|
|
145
|
+
│ ├── paypal/
|
|
146
|
+
│ └── chargebee/
|
|
147
|
+
├── subscription/
|
|
148
|
+
│ └── check/ # Check active subscriptions
|
|
149
|
+
└── cron/
|
|
150
|
+
└── abandoned-carts/ # Daily cron for emails
|
|
151
|
+
|
|
152
|
+
Key Implementation Points
|
|
153
|
+
|
|
154
|
+
1. IP Address Tracking: Add to schema and capture in /payment-v2/intent
|
|
155
|
+
2. Composite Indexes: Create for efficient queries:
|
|
156
|
+
- payment-subscriptions: userId + productId + status
|
|
157
|
+
- payment-trials: uid + productId + app, ipAddress + productId + app
|
|
158
|
+
3. Unified Status Mapping: Create processor-agnostic status values
|
|
159
|
+
4. Webhook Security: Verify signatures for each processor
|
|
160
|
+
5. App Notifications: Implement retry logic with exponential backoff
|
|
161
|
+
|
|
162
|
+
Would you like me to start implementing any of these components? I'd suggest starting with:
|
|
163
|
+
1. Updating the intent endpoint to check active subscriptions
|
|
164
|
+
2. Enhancing trial eligibility to include IP checking
|
|
165
|
+
3. Creating the abandoned cart tracking endpoint
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
1. Unified Endpoint Structure
|
|
3
|
+
|
|
4
|
+
All processors now use the same endpoint:
|
|
5
|
+
- Production: https://api.itwcreativeworks.com/payment/intent?processor={PROCESSOR}
|
|
6
|
+
- Development: http://localhost:5001/your-project-id/us-central1/api/payment/intent?processor={PROCESSOR}
|
|
7
|
+
|
|
8
|
+
The endpoint automatically switches based on webManager.isDevelopment().
|
|
9
|
+
|
|
10
|
+
2. Standardized Request Body
|
|
11
|
+
|
|
12
|
+
All processors send the same request structure:
|
|
13
|
+
{
|
|
14
|
+
processor: 'stripe' | 'paypal' | 'chargebee',
|
|
15
|
+
recaptcha_token: 'token_from_google',
|
|
16
|
+
processor_data: { /* processor-specific data */ },
|
|
17
|
+
api_key: 'processor_api_key',
|
|
18
|
+
is_subscription: true/false // for PayPal
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
3. Backend Architecture (Firebase Functions)
|
|
22
|
+
|
|
23
|
+
Your backend can now have a clean structure:
|
|
24
|
+
/functions
|
|
25
|
+
/payment
|
|
26
|
+
- intent.js // Main handler
|
|
27
|
+
/modules
|
|
28
|
+
- recaptcha.js // Shared reCAPTCHA verification
|
|
29
|
+
- stripe.js // Stripe-specific logic
|
|
30
|
+
- paypal.js // PayPal-specific logic
|
|
31
|
+
- chargebee.js // Chargebee-specific logic
|
|
32
|
+
|
|
33
|
+
The main handler can:
|
|
34
|
+
1. Verify reCAPTCHA token (common for all)
|
|
35
|
+
2. Extract processor from query param
|
|
36
|
+
3. Validate request body
|
|
37
|
+
4. Delegate to appropriate processor module
|
|
38
|
+
5. Return standardized response: { url: "checkout_url" }
|
|
39
|
+
|
|
40
|
+
This architecture makes it easy to:
|
|
41
|
+
- Add new payment processors
|
|
42
|
+
- Share common logic (reCAPTCHA, logging, error handling)
|
|
43
|
+
- Test locally with Firebase emulator
|
|
44
|
+
- Maintain consistent API structure
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/// SUBSCRIPTION
|
|
2
|
+
|
|
3
|
+
{
|
|
4
|
+
// Core identification
|
|
5
|
+
id: "sub-xxx", // Or "ORD-xxx" for orders
|
|
6
|
+
app: "app-id",
|
|
7
|
+
product: "product-id",
|
|
8
|
+
checkout: "chk-xxx", // Links back to payment-intents
|
|
9
|
+
|
|
10
|
+
// Auth
|
|
11
|
+
auth: {
|
|
12
|
+
uid: "user-uid",
|
|
13
|
+
email: "user@example.com"
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
// Processor information
|
|
17
|
+
processor: {
|
|
18
|
+
id: "stripe", // stripe, paypal, chargebee
|
|
19
|
+
lastWebhookEvent: "customer.subscription.updated" // Useful for debugging
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// Type identifier
|
|
23
|
+
type: "subscription", // or "order" for one-time
|
|
24
|
+
|
|
25
|
+
// Status information
|
|
26
|
+
status: "active", // Same statuses work for orders too
|
|
27
|
+
access: true, // Computed based on current status and rules
|
|
28
|
+
frequency: "monthly", // null for one-time orders
|
|
29
|
+
|
|
30
|
+
// Customer information
|
|
31
|
+
customer: {
|
|
32
|
+
id: "cus-xxx", // Customer ID in the processor
|
|
33
|
+
name: "John Doe",
|
|
34
|
+
email: "john.doe@example.com"
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Billing information
|
|
38
|
+
billing: {
|
|
39
|
+
amount: 99.99,
|
|
40
|
+
lastPayment: {
|
|
41
|
+
amount: 99.99,
|
|
42
|
+
date: {
|
|
43
|
+
timestamp: "2023-10-01T12:00:00Z",
|
|
44
|
+
timestampUNIX: 1696156800
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
totalRevenue: 299.97, // Lifetime value
|
|
48
|
+
paymentCount: 3 // Number of successful payments
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Trial information (if applicable)
|
|
52
|
+
trial: {
|
|
53
|
+
active: true, // Is the trial currently active?
|
|
54
|
+
claimed: true, // Actually used the trial
|
|
55
|
+
days: 14,
|
|
56
|
+
started: {
|
|
57
|
+
timestamp: "2023-09-15T12:00:00Z",
|
|
58
|
+
timestampUNIX: 1694745600 // UNIX timestamp
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Supplemental information from the checkout form
|
|
63
|
+
supplemental: {
|
|
64
|
+
// Custom form fields
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Analytics and tracking
|
|
68
|
+
utm: {
|
|
69
|
+
source: "google",
|
|
70
|
+
medium: "cpc",
|
|
71
|
+
campaign: "summer_sale",
|
|
72
|
+
content: "ad_1",
|
|
73
|
+
term: "keyword"
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// Original processor data (for debugging)
|
|
77
|
+
raw: {
|
|
78
|
+
// Complete webhook payload or API response
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Metadata and timestamps
|
|
82
|
+
meta: {
|
|
83
|
+
created: {
|
|
84
|
+
timestamp: "2023-10-01T12:00:00Z",
|
|
85
|
+
timestampUNIX: 1696156800
|
|
86
|
+
},
|
|
87
|
+
updated: {
|
|
88
|
+
timestamp: "2023-10-02T12:00:00Z",
|
|
89
|
+
timestampUNIX: 1696243200
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
ok so i need help planning the storage, trial eligibility, and webhooks. im not exactly sure WHAT to store and WHEN to store it. But heres what i know so far
|
|
2
|
+
|
|
3
|
+
* This system we are building is a centralized checkout system for multiple apps that offer multiple products
|
|
4
|
+
* This is why we store and keep track of the "app" and "product id" in the database and http calls.
|
|
5
|
+
|
|
6
|
+
* Prevent users who HAVE A SUBSCRIPTION from buying another one
|
|
7
|
+
* We will need to check our database to see if the user has an active subscription, as in one that is not cancelled.
|
|
8
|
+
* If the user has an active subscription, they should NOT be able to buy another one.
|
|
9
|
+
|
|
10
|
+
* We need to keep track of which users have had a trial already.
|
|
11
|
+
* There is TRIAL OFFERING and TRIAL ELIGIBILITY. TRIAL OFFERING means a product offers the possibility of a trial (stored in the app.products.[product-id].trial as either 0 or a number of days), and TRIAL ELIGIBILITY means the user is eligible for a trial, which is TRUE if the user has never used a trial for THAT PRODUCT in THAT APP .
|
|
12
|
+
* For this we need to store the "app", the "product.id", the "auth.uid", and the "geolocation.ip". In other words, for every product in a given app, we cant let a person use the trial more than once. So we should search for a product id of an app and if EITHER the UID or the IP address is found, then we should not allow the user to use the trial. A user can take a trial for a DIFFERNT product in the same app, or a different app entirely. Its only for the same product in the same app that we should not allow a trial more than once.
|
|
13
|
+
* This is because we dont want people to abuse the trial system.
|
|
14
|
+
* If the product DOES NOT OFFER A TRIAL, then we should not even check for a trial and assume they are not eligible for one.
|
|
15
|
+
|
|
16
|
+
* I want to implement a custom "abandoned cart" system
|
|
17
|
+
* The moment a user lands on the checkout page, we will store the cart somewhere in our database by sending an HTTP request to our server with the cart data.
|
|
18
|
+
* This way, we can loop through every day and if the user has not completed their checkout, we can send them an email reminding them to complete their purchase, one at 1 day, 3 days, and 7 days after they first landed on the checkout page. The link to go back will have their unique checkout ID in the URL.
|
|
19
|
+
* When they go to the checkout and send the request to our server, we will check if there is a cart with that ID, and if so, we will reset that cart's timer so we can send more abandoned cart emails if they still do not complete their purchase.
|
|
20
|
+
* Essentially, every time they visit checkout we will check if they have an abandoned cart, and if so, we will reset the timer for that cart.
|
|
21
|
+
|
|
22
|
+
* We need to set up webhook listener for stripe, paypal, etc
|
|
23
|
+
* Update the database with subscription events like when it becomes active, cancelled, etc.
|
|
24
|
+
* When we receive an event for say, subscription cancelled, we will need to find the record and update the status
|
|
25
|
+
* Without getting too ahead of ourselves, I would like to DESIGN A PROPRIETARY and UNIFIED object that we can use to store the subscription data and status. This way, no matter what payment provider we use, we can ensure the user has access to their paid features etc without having to consider all the different payment providers own data structures. In this sense, we will create a "resolved" subscription object that contains data regarding when the subscription started, whether it is active/cancelled/suspended (meaning unpaid), the payment provider, the product id, the app id, and any other relevant data we need to store. This way, we can use this object to check if a user has an active subscription or not, regardless of the payment provider.
|
|
26
|
+
* Also without getting too ahead of ourselves, we will need to send our own HTTP requests to the individual APP that is usinng our unified checkout system. So essentialy we will send a request with the subscription data AND THE RESOLVED SUBSCRIPTION OBJECT to the app that is using our checkout system. This way, the app can update its own database with the subscription data and status, and we can ensure that the user has access to their paid features in THAT SPECIFIC APP.
|
|
27
|
+
|
|
28
|
+
SO... ALL OF THE ABOVE CONSIDERED... Where should all of these checks happen and where should we store the data? By that I mean, which server functions do we perform these checks and what collections in firestore do we need?
|
|
29
|
+
* Do we store the entire lifecycle of an order in one collection? Or do we store parts of it in different collections?
|
|
30
|
+
* Storing in ONE COLLECTION
|
|
31
|
+
* we would store all the trial related data, the app, product, user, and geolocation data in one collection
|
|
32
|
+
* We would have a status field that indicates at what stage the order is in such as if its just a payment intent or if it was completed
|
|
33
|
+
* Storing in multiple collections
|
|
34
|
+
* We would only store what we need for the specific operation, like we could habe a "payment-trials" collection that keeps track of app, product, user, and IP address, and a "payment-orders" collection that keeps track of the order status, payment provider, etc. and then a "payment-subscriptions" collection that keeps track of the subscription status, start date, end date, etc.
|
|
35
|
+
|
|
36
|
+
SO... What is the best way to store this data and what endpoints should we set up?
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Core Subscription Statuses
|
|
2
|
+
|
|
3
|
+
pending
|
|
4
|
+
- Initial state after checkout
|
|
5
|
+
- Access = false
|
|
6
|
+
- Waiting for first payment confirmation
|
|
7
|
+
- Becomes active or expired
|
|
8
|
+
- Requires additional user action (3D Secure, bank approval)
|
|
9
|
+
|
|
10
|
+
active
|
|
11
|
+
- Subscription is paid and current
|
|
12
|
+
- Access = true
|
|
13
|
+
- Payment method is valid
|
|
14
|
+
- Next billing date is in the future
|
|
15
|
+
|
|
16
|
+
trialing
|
|
17
|
+
- User is in free trial period
|
|
18
|
+
- Access = true
|
|
19
|
+
- No charges yet
|
|
20
|
+
- Will convert to active or cancelled when trial ends
|
|
21
|
+
|
|
22
|
+
paused
|
|
23
|
+
- Temporarily halted by user/admin
|
|
24
|
+
- Access = ?
|
|
25
|
+
- No charges during pause
|
|
26
|
+
- Can be resumed
|
|
27
|
+
- Access may be retained or revoked (configurable)
|
|
28
|
+
- ??? How do we determine access?
|
|
29
|
+
|
|
30
|
+
suspended
|
|
31
|
+
- One or more payments failed
|
|
32
|
+
- Access = false
|
|
33
|
+
- Access revoked
|
|
34
|
+
- Can be reactivated if payment succeeds
|
|
35
|
+
- Not permanently cancelled
|
|
36
|
+
|
|
37
|
+
cancelled
|
|
38
|
+
- User intentionally cancelled
|
|
39
|
+
- Access = true
|
|
40
|
+
- Will have access until period end
|
|
41
|
+
- No future charges
|
|
42
|
+
- Transitions to expired at period end
|
|
43
|
+
|
|
44
|
+
expired
|
|
45
|
+
- Subscription period ended after cancellation
|
|
46
|
+
- Access = false
|
|
47
|
+
- Cannot be reactivated (must create new subscription)
|
|
48
|
+
- Terminal state
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Stripe → Unified
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
'trialing': 'trialing',
|
|
55
|
+
'active': 'active',
|
|
56
|
+
'incomplete': 'incomplete',
|
|
57
|
+
'incomplete_expired': 'expired',
|
|
58
|
+
'past_due': 'past_due',
|
|
59
|
+
'canceled': 'cancelled',
|
|
60
|
+
'unpaid': 'suspended',
|
|
61
|
+
'paused': 'paused'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
PayPal → Unified
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
'APPROVAL_PENDING': 'pending',
|
|
68
|
+
'APPROVED': 'pending',
|
|
69
|
+
'ACTIVE': 'active',
|
|
70
|
+
'SUSPENDED': 'suspended',
|
|
71
|
+
'CANCELLED': 'cancelled',
|
|
72
|
+
'EXPIRED': 'expired'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Chargebee → Unified
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
'future': 'pending',
|
|
79
|
+
'in_trial': 'trialing',
|
|
80
|
+
'active': 'active',
|
|
81
|
+
'non_renewing': 'cancelled',
|
|
82
|
+
'paused': 'paused',
|
|
83
|
+
'cancelled': 'expired',
|
|
84
|
+
'transferred': 'expired'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Status Transition Rules
|
|
88
|
+
|
|
89
|
+
const validTransitions = {
|
|
90
|
+
'pending': ['active', 'trialing', 'incomplete', 'expired'],
|
|
91
|
+
'trialing': ['active', 'cancelled', 'suspended'],
|
|
92
|
+
'active': ['cancelled', 'suspended', 'paused'],
|
|
93
|
+
'suspended': ['active', 'cancelled', 'expired'],
|
|
94
|
+
'cancelled': ['expired'], // Can only expire after cancellation
|
|
95
|
+
'paused': ['active', 'cancelled', 'expired'],
|
|
96
|
+
'incomplete': ['active', 'expired'],
|
|
97
|
+
'expired': [] // Terminal state
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
function computeAccess(subscription) {
|
|
102
|
+
switch (subscription.status) {
|
|
103
|
+
case 'active':
|
|
104
|
+
case 'trialing':
|
|
105
|
+
return true;
|
|
106
|
+
|
|
107
|
+
case 'cancelled':
|
|
108
|
+
// Has access until current period ends
|
|
109
|
+
return subscription.billing.currentPeriodEnd > Date.now();
|
|
110
|
+
|
|
111
|
+
case 'paused':
|
|
112
|
+
// Use stored decision from when pause was created
|
|
113
|
+
return subscription.pause?.accessRetained ?? false;
|
|
114
|
+
|
|
115
|
+
case 'pending':
|
|
116
|
+
case 'suspended':
|
|
117
|
+
case 'expired':
|
|
118
|
+
return false;
|
|
119
|
+
|
|
120
|
+
default:
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Frontend TODO
|
|
2
|
+
- sentry in WM
|
|
3
|
+
- chatsy
|
|
4
|
+
- remake chatsy into a module that we can install here and then users can load it via cdnjs instead of our website
|
|
5
|
+
- contact form with tracking and form-manager and slapform
|
|
6
|
+
|
|
7
|
+
- save utm tags, send during checkout, signup, etc
|
|
8
|
+
|
|
9
|
+
- token redirect for auth system (for auth with desktop apps, etc)
|
|
10
|
+
|
|
11
|
+
ensure blog, article, posts, etc all use proper HTML semantics tags, aria, etc
|
|
12
|
+
|
|
13
|
+
js refactor
|
|
14
|
+
- make all fns await asyn operations
|
|
15
|
+
- order the fn definitions in the order they are called (most import/toplevel first then the rest. put all tracking fns at the bottom)
|
|
16
|
+
- move export to top and do not use init() fn, just call all fns inside dom.ready OR the main export (depends on the structure)
|
|
17
|
+
- track errors w sentry, not ga4/fb/tiktok
|
|
18
|
+
- add Manager, options back to each index.js for standardization
|
|
19
|
+
- for stanndardization, also ALWAYS set webManager = Manager.webManager in the index.js
|
|
20
|
+
|
|
21
|
+
pages
|
|
22
|
+
- blog + post
|
|
23
|
+
- about
|
|
24
|
+
- contact
|
|
25
|
+
- team + member
|
|
26
|
+
- extension and download
|
|
27
|
+
|
|
28
|
+
MAKE OUR CUSTOM THEME CLASSY!!
|
|
29
|
+
|
|
30
|
+
for pages like pricing, home, about etc
|
|
31
|
+
- put default frontmatter in the default pages so user can override
|
|
32
|
+
|
|
33
|
+
NEW PLAN NAME STANDARD
|
|
34
|
+
1. Basic, Starter, Pro, Max
|
|
35
|
+
1. Basic, Starter, Plus, Pro
|
|
36
|
+
|
|
37
|
+
Implement account resolver
|
|
38
|
+
|
|
39
|
+
https://docs.stripe.com/payments/link/express-checkout-element-link
|
|
40
|
+
|
|
41
|
+
// // Load page specific scripts
|
|
42
|
+
// if (url.includes('/pricing')) {
|
|
43
|
+
// dom.loadScript({src: 'https://cdn.itwcreativeworks.com/assets/general/js/pricing-page-handler/index.js'})
|
|
44
|
+
// } else if (url.includes('/download')) {
|
|
45
|
+
// dom.loadScript({src: 'https://cdn.itwcreativeworks.com/assets/general/js/download-page-handler/index.js'})
|
|
46
|
+
// } else if (url.includes('/browser-extension') || url.includes('/extension')) {
|
|
47
|
+
// dom.loadScript({src: 'https://cdn.itwcreativeworks.com/assets/general/js/browser-extension-page-handler/index.js'})
|
|
48
|
+
// } else if (window.location.pathname.endsWith('.html')) {
|
|
49
|
+
// // Redirect and remove .html
|
|
50
|
+
// window.location.pathname = window.location.pathname.replace('.html', '');
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// // Save user auth data
|
|
56
|
+
// Manager.auth().ready(function (user) {
|
|
57
|
+
// setupTracking(user);
|
|
58
|
+
|
|
59
|
+
// storage.set('user.auth.uid', user.uid);
|
|
60
|
+
// storage.set('user.auth.email', user.email);
|
|
61
|
+
// })
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="800" width="1200" viewBox="-120.015 -200 1040.13 1200"><linearGradient y2="800" x2="400" y1="0" x1="400" gradientUnits="userSpaceOnUse" id="a"><stop offset="0" stop-color="#0ed4fc"/><stop offset="1" stop-color="#0c57ef"/></linearGradient><path d="M638.4 0H161.6C72.3 0 0 72.3 0 161.6v476.9C0 727.7 72.3 800 161.6 800h476.9c89.2 0 161.6-72.3 161.6-161.6V161.6C800 72.3 727.7 0 638.4 0z" fill="url(#a)"/><path d="M396.6 183.8l16.2-28c10-17.5 32.3-23.4 49.8-13.4 17.5 10 23.4 32.3 13.4 49.8L319.9 462.4h112.9c36.6 0 57.1 43 41.2 72.8H143c-20.2 0-36.4-16.2-36.4-36.4s16.2-36.4 36.4-36.4h92.8l118.8-205.9-37.1-64.4c-10-17.5-4.1-39.6 13.4-49.8 17.5-10 39.6-4.1 49.8 13.4zM256.2 572.7l-35 60.7c-10 17.5-32.3 23.4-49.8 13.4-17.5-10-23.4-32.3-13.4-49.8l26-45c29.4-9.1 53.3-2.1 72.2 20.7zm301.4-110.1h94.7c20.2 0 36.4 16.2 36.4 36.4s-16.2 36.4-36.4 36.4h-52.6l35.5 61.6c10 17.5 4.1 39.6-13.4 49.8-17.5 10-39.6 4.1-49.8-13.4-59.8-103.7-104.7-181.3-134.5-233-30.5-52.6-8.7-105.4 12.8-123.3 23.9 41 59.6 102.9 107.3 185.5z" fill="#fff"/></svg>
|