Skip to content

feat(wrapped): integrate WhatsApp Wrapped into /wrapped route - #388

Open
fellnerse wants to merge 16 commits into
devfrom
feat/integrate-wrapped
Open

feat(wrapped): integrate WhatsApp Wrapped into /wrapped route#388
fellnerse wants to merge 16 commits into
devfrom
feat/integrate-wrapped

Conversation

@fellnerse

Copy link
Copy Markdown
Member

Summary

Migrates the standalone WhatsApp Wrapped application (whatsanalyze-wrapped) into the main repository under the /wrapped route hierarchy. This consolidates domain equity onto the primary domain, improves user conversion flow, and keeps Wrapped and WhatsAnalyze neatly organized.

Key Changes

  • Styling Isolation: Configured Tailwind CSS with preflight: false in tailwind.config.mjs and scoped CSS in assets/wrapped/tailwind.css to ensure complete style isolation without conflicts with Vuetify.
  • Dedicated Layout & Pages:
    • layouts/wrapped.vue: Isolated dark-mode layout with Wrapped header, language switcher, and footer.
    • pages/wrapped/index.vue: Landing and chat upload interface with dynamic target year recap logic.
    • pages/wrapped/results.vue: Full story carousel running all 11 story slides (Intros, Emojis, Words, Conversations, and Encrypted Share).
    • pages/wrapped/subscription/*: Verification, success, and cancelation flows for Stripe subscriptions.
  • State & Analyzers:
    • Added Pinia (@pinia/nuxt) and pinia-plugin-persistedstate under stores/wrapped/ with sessionStorage persistence.
    • Migrated modular analyzers (utils/wrapped/parsing/) and web-worker parser (assets/wrapped/workers/).
  • Dual Firebase & Encrypted Sharing:
    • Configured a secondary Firebase instance (wrappedFirebase) in plugins/firebase.client.js pointing to whatsanalyze-wrapped-prod Firestore, preserving existing client-side AES-GCM encrypted share links.
  • Localization & Routing:
    • Merged Wrapped locale dictionaries (en, de, es, fr, it, pt) in i18n/i18n.config.js.
    • Added wrapped routes to localizedPages in nuxt.config.js for full static prerendering across all supported languages.
    • Updated home page banner and whatsapp-wrapped-year-review to link internally to localePath('/wrapped').

Verification

  • pnpm generate: Successfully prerendered all 112 static routes and generated PWA service worker with 261 precache entries.
  • pnpm test:generated: Verified all 15 expected pages in dist/.
  • pnpm test: Jest unit tests passed (4/4).
  • pnpm playwright test tests/e2e/wrapped.spec.js: Passed on Desktop Chromium and Mobile Chromium (6/6).
  • Full e2e suite: Passed across both projects (18 tests).

@mowolf
mowolf changed the base branch from tools to dev September 5, 2026 17:37
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit 4aa8a0d):

https://whatsanalyze-80665--pr388-feat-integrate-wrapp-gj3hq9ly.web.app

(expires Tue, 15 Sep 2026 07:26:15 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 5796a863d3a1b99df3fcb31feec7a39514d97aa4

@fellnerse

fellnerse commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

😈 Devil's Advocate Review: WhatsAnalyze Wrapped Integration

Comprehensive architectural, functional, and visual audit comparing standalone (wrapped.whatsanalyze.com from SpiritFour/whatsanalyze-wrapped) vs. integrated (/wrapped on feat/integrate-wrapped).


🚨 Critical Bugs & Broken Functionality

  1. Broken Share Link Destination (/results instead of /wrapped/results):

    • In components/wrapped/Stories/ShareInvite.vue line 98:
      return `${normalizedBase}/results?${queryString}`;
    • Impact: On the standalone domain, /results was the root path. Inside WhatsAnalyze, /results does not exist or routes to main app results, leading to a 404 or broken page for anyone clicking a shared Wrapped story.
    • Fix: Must use localePath('/wrapped/results') so the generated link points to /wrapped/results?uuid=...&iv=...&key=....
  2. Dual Firebase App Conflict on Cloud Functions:

    • In plugins/firebase.client.js:
      const app = initializeApp(config.public.firebase); // whatsanalyze-80665
      const functions = getFunctions(app);
      
      if (config.public.wrappedFirebase) {
        const wrappedApp = initializeApp(config.public.wrappedFirebase, "wrapped"); // whatsanalyze-wrapped-prod
        wrappedFirestore = getFirestore(wrappedApp);
        wrappedFunctions = getFunctions(wrappedApp);
      }
      ...
      provide: {
        firestore: wrappedFirestore,
        functions: wrappedFunctions, // OVERRIDES default functions!
      }
    • Impact:
      • useNuxtApp().$functions now points to whatsanalyze-wrapped-prod.
      • In components/SubscribeBtn.vue and components/SubscriptionChecker.vue, PayPal subscription status calls checksubscriberstatus and helloworld against $firebase.callFunction, which uses the primary functions. If any main app feature relies on $functions, it now points to Wrapped's Firebase project.
      • Conversely, in pages/wrapped/subscription/verify.vue and success.vue, Stripe calls getCheckoutSession, verifySubscription, and createCustomerPortal through useNuxtApp().$functions. If wrappedFunctions failed to init or config differs, calls fail or route to the wrong project.
    • Fix: Disambiguate services explicitly in plugins/firebase.client.js:
      • Provide $firestore (main) and $wrappedFirestore (wrapped)
      • Provide $functions (main) and $wrappedFunctions (wrapped)
      • Update pages/wrapped/subscription/*.vue and utils/wrapped/subscription.ts to explicitly call $wrappedFunctions.
  3. Missing Firebase Analytics in Nuxt Plugin:

    • useAnalytics.ts looks up nuxtApp.$analytics, but plugins/firebase.client.js does not initialize or provide analytics (getAnalytics).
    • Impact: All telemetry (file_upload, story_slide_viewed, subscription_started, share_created) silently drops with no events recorded in GA4.
  4. Background CSS Asset Path Mismatch:

    • In assets/wrapped/tailwind.css:
      .wrapped-scope .bg-whatsapp {
        background: url("/wrapped/backgrounds/light.png") repeat;
      }
    • In static/: files are located at static/backgrounds/light.png (served at /backgrounds/light.png), not /wrapped/backgrounds/light.png.
    • Impact: CSS background pattern is 404/broken on elements styled with .bg-whatsapp.

⚠️ Functional & Behavioral Differences

  1. State Isolation & Storage Lifecycle:
    • Standalone: Pure SPA on its own origin; sessionStorage strictly held Wrapped state.
    • Integrated: Shares domain storage with WhatsAnalyze. If a user navigates between WhatsAnalyze tools and /wrapped, Pinia persisted state lives on the same origin. Ensure keys (stats, user-data, subscription) are prefixed or namespaced so they do not collide with existing or future main app stores.
  2. Double Payment System Coexistence:
    • Main WhatsAnalyze uses PayPal subscriptions (via checksubscriberstatus).
    • Wrapped uses Stripe subscriptions with price price_1SgOxVL4rDqbYflowSbSteJQ.
    • Users who subscribed on WhatsAnalyze Pro won't have Pro on Wrapped, and vice-versa, creating confusion unless documented or unified.

-> We will not tackle this now, but in a second stage. So ignore this issue. (Double payment)

  1. Audio Autoplay Restrictions:
    • components/wrapped/Style/BlueSlider.vue plays /sounds/whoosh.mp3 on slide changes. On mobile browsers and Chromium, unmuted audio triggered outside direct click gestures can throw NotAllowedError (partially caught by .catch(), but audio remains silent).

🎨 Visual & Layout Differences

  1. Header & Navigation Coherence:
    • Standalone had its own dedicated header with standalone Wrapped logo.
    • Integrated keeps an isolated Wrapped header via layouts/wrapped.vue, but completely disconnects from WhatsAnalyze main navigation (no link back to /, Tools, or Main Analyzer except clicking the logo which goes to /wrapped).
    • Users entering /wrapped have no breadcrumb or intuitive way to navigate back to the main suite.
  2. Missing About Component / Disabled Landing Sections:
    • pages/wrapped/index.vue commented out media cards, celebration stories, and AI highlights present in the original template.
    • About.vue was renamed to WrappedAbout.vue and static image paths adjusted; verify team photos load properly from /img/us/*.jpg.
  3. Tailwind Preflight & Scoping Inconsistencies:
    • preflight: false was set in tailwind.config.mjs to protect Vuetify. However, certain raw Tailwind utility classes rely on CSS resets (e.g., border colors defaulting to currentColor, default margins/paddings). In .wrapped-scope, explicit borders or resets should be checked across buttons and inputs.

📋 Recommended Adjustments Before Merging

  • Fix share URL builder in components/wrapped/Stories/ShareInvite.vue to prepend /wrapped.
  • Explicitly separate $wrappedFunctions and $wrappedFirestore in plugins/firebase.client.js to eliminate Firebase project collisions.
  • Initialize getAnalytics in plugins/firebase.client.js and provide $analytics.
  • Fix .bg-whatsapp background URL in assets/wrapped/tailwind.css to /backgrounds/light.png (or relocate assets under static/wrapped/).
  • Add a subtle link/badge in layouts/wrapped.vue pointing back to WhatsAnalyze main app (/).
  • Plan customer billing alignment between PayPal (WhatsAnalyze) and Stripe (Wrapped).

root added 3 commits September 6, 2026 15:34
…e links, and layout

- Disambiguate primary and wrapped Firebase services (,  vs , )
- Initialize and provide Firebase Analytics for telemetry tracking
- Update share link destination in ShareInvite to /wrapped/results
- Fix WhatsApp background asset URL path in tailwind.css
- Add link back to WhatsAnalyze main app in wrapped layout with localized strings
@fellnerse
fellnerse force-pushed the feat/integrate-wrapped branch from 27bd6df to 23468ec Compare September 6, 2026 15:36
@fellnerse

This comment was marked as resolved.

@fellnerse

This comment was marked as resolved.

@fellnerse

This comment was marked as resolved.

@fellnerse

Copy link
Copy Markdown
Member Author

Review: Current origin/feat/integrate-wrapped Functionality Issues

After analyzing and testing the current origin branch against the original whatsanalyze-wrapped implementation, chat upload and processing are currently non-functional. Below is a breakdown of the critical issues:


1. 🚨 Blocker: Chat Parser Worker Throws TypeError: e.filter is not a function

  • Location: utils/wrapped/parsing/index.ts line 50
  • Issue:
    const messages = whatsapp.parseString(textData, {
      parseAttachments: true,
    });
    const validMessages = this.filterValidMessages(messages);
  • Cause: The project dependency is whatsapp-chat-parser@^3.2.3. In this version, whatsapp.parseString(...) returns a Promise<Message[]>. Because it is not awaited, messages is a Promise, causing filterValidMessages to call .filter() on a Promise and fail immediately.
  • Impact: Every upload fails in the Web Worker; sendFile() rejects and the page never transitions to /wrapped/results.
  • Fix: Await the call:
    const messages = await whatsapp.parseString(textData, {
      parseAttachments: true,
    });
    (or use whatsapp.parseStringSync(textData, ...)).

2. ⚠️ Strict Target Year Filter Excludes All Historical / Test Chats

  • Location: utils/wrapped/parsing/index.ts & utils/wrapped/dateUtils.ts
  • Issue:
    msg.date.getFullYear() === getTargetYear()
    getTargetYear() only targets the previous year (currently 2025 until December 2026).
  • Impact: Any test chat or export without messages in the target year results in validMessages = [], leaving the story slides empty/broken with no feedback to the user.
  • Recommendation: Add a fallback or banner if 0 messages match the target year, or handle chats spanning other years gracefully.

3. ❌ Secondary Firebase App / Functions Mismatch on Origin

  • Locations:
    • utils/wrapped/sharing/firestore.ts
    • utils/wrapped/subscription.ts
    • pages/wrapped/subscription/verify.vue
    • pages/wrapped/subscription/success.vue
  • Issue: These files call useNuxtApp().$firestore and useNuxtApp().$functions, pointing to the primary WhatsAnalyze Firebase instance rather than the secondary wrappedFirebase instance initialized in plugins/firebase.client.js.
  • Impact: Creating share links and verifying subscriptions fails due to missing or wrong Firebase project references.
  • Fix: Fall back to $wrappedFirestore / $wrappedFunctions (as implemented in the local working tree changes).

4. 🖼️ Broken CSS Background Asset Path on Origin

  • Location: assets/wrapped/tailwind.css
  • Issue: background: url("/wrapped/backgrounds/light.png") repeat; 404s because the static file was placed at /backgrounds/light.png.
  • Fix: Update path to url("/backgrounds/light.png").

5. 🔗 Share Invite Link URL

  • Location: components/wrapped/Stories/ShareInvite.vue
  • Issue: Resolving the base URL for the share link hardcodes /results?${queryString} instead of localized /wrapped/results.
  • Fix: Use localePath('/wrapped/results').

@fellnerse

Copy link
Copy Markdown
Member Author

sharing does not work:
B9NaKnXY.js:50 Failed to share story FirebaseError: Missing or insufficient permissions.
le @ B9NaKnXY.js:50
await in le
gn @ CbvVMG-D.js:1
B @ CbvVMG-D.js:1
n @ BXXPikuK.js:1
CuoOMdHc.js:38 POST https://firestore.googleapis.com/google.firestore.v1.Firestore/Write/channel?VER=8&database=projects%2Fwhatsanalyze-wrapped%2Fdatabases%2F(default)...
net::ERR_BLOCKED_BY_CLIENT

@mowolf

mowolf commented Sep 7, 2026

Copy link
Copy Markdown
Member
image

still looks very broken.

White bottom needs to be fixed with ios color option

code needs to be copied not reverse engineered from the whatsanalyze wrapped repo. It is already vue 3 and you missed a lot of stuff eg background gradients etc

@mowolf

mowolf commented Sep 7, 2026

Copy link
Copy Markdown
Member

Good job. Now I still see the gradient circles look off. They are supposed to be smooth

How it looks now:
image

How it used to look in /wrapped repo:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants