Skip to content

Enhance WhatsApp generator with phone conversion and QR colors#1

Merged
juliolmuller merged 11 commits into
mainfrom
feat/layout-improvement
May 12, 2026
Merged

Enhance WhatsApp generator with phone conversion and QR colors#1
juliolmuller merged 11 commits into
mainfrom
feat/layout-improvement

Conversation

@juliolmuller

@juliolmuller juliolmuller commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • QR color customization
    • Required-field indicators for phone and business short code
  • UI/UX Improvements

    • Responsive form grid and refined preview panel
    • Preview title changed to “Result”
    • Improved phone number handling and validation
  • Accessibility

    • ARIA-required and screen-reader announcements for required fields
  • Tests

    • Added phone parsing unit tests
  • Chores

    • Repository links updated; repository ownership and lint script updated

Review Change Stack

juliolmuller and others added 5 commits May 11, 2026 16:43
…hints, and include DDI in URL

UX improvements for the generator:

- Result panel: reorder to URL+actions first (full width), then QR (left)
  and chat preview (right) on wider screens; rename "Preview" to "Result";
  hide chat preview when no message; recenter QR at one-column width when
  chat preview is hidden.
- Form: full-width container, two-column on wider screens, with the UTM
  fieldset and action row spanning both columns; mark phone/short code as
  required (red asterisk via Label) and message as optional; debounce URL
  computation by 600ms via useWatch + useDebouncedValue, with the parent
  onChange wrapped in a ref so identity changes don't re-fire the effect.
- Shell: hide the entire result panel until a phone (or short code, for
  business links) is provided, so the preview never renders empty state.
- URL building: always include the country dialing code (DDI) in
  generated wa.me / api.whatsapp.com / whatsapp:// URLs by transforming
  the raw input through libphonenumber-js (with a heuristic prepend
  fallback for partial input). Adds src/lib/phone.test.ts with vitest
  coverage for empty input, valid BR/US numbers, E.164 round-trip, and
  partial-typing fallback.

Co-authored-by: Claude Opus <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…iners

Add `justify-end` to the flex rows hosting Reset/Share, Copy/Open URL,
and Download PNG/SVG, so primary actions consistently anchor to the
right edge of their containers across both panels.

Co-authored-by: Claude Opus <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add a color picker to the QR preview controls so users can recolor the
foreground (dark cells) of the generated code. Defaults to the existing
WhatsApp-deep-green (#075E54) and flows through the on-screen canvas
preview as well as the PNG/SVG downloads.

- src/lib/qrcode.ts: export QR_DEFAULT_DARK_COLOR / QR_DEFAULT_LIGHT_COLOR
  so the component shares the source of truth for defaults.
- src/components/generator/QrPreview/QrPreview.tsx: add `color` state,
  pipe `darkColor` through drawToCanvas/downloadPng/downloadSvg, and add
  a native <input type="color"> sized to match the adjacent
  error-correction <select> for visual harmony. Controls grid relaxed to
  sm:grid-cols-2 lg:grid-cols-4 to host the new field.
- i18n: new `qr.color` key in en, es and pt-BR.

Co-authored-by: Claude Opus <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Update the repository URL referenced from the header and footer to the
new canonical location under the LacusSolutions organization.

Co-authored-by: Claude Opus <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented May 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openzap Ready Ready Preview, Comment May 12, 2026 7:09pm

@juliolmuller

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@juliolmuller has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 39 minutes and 18 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 844bbfa4-9aa2-4475-b696-a0cda486c58e

📥 Commits

Reviewing files that changed from the base of the PR and between 1bf35c4 and 2d01790.

📒 Files selected for processing (4)
  • src/components/generator/PhoneField/PhoneField.tsx
  • src/components/ui/Label/Label.tsx
  • src/lib/phone.test.ts
  • src/lib/phone.ts
📝 Walkthrough

Walkthrough

This PR enhances the WhatsApp generator app with phone number-to-WhatsApp-digits utility conversion, QR code color customization, required form field indicators, debounced URL computation to reduce re-renders, and refactored conditional preview rendering. It updates translations across three languages, adjusts layout components, and updates repository links.

Changes

Core Feature: Phone Utility, QR Colors, and Enhanced Form Fields

Layer / File(s) Summary
QR and Phone Utility Libraries
src/lib/qrcode.ts, src/lib/phone.ts, src/lib/phone.test.ts
Introduces QR_DEFAULT_DARK_COLOR and QR_DEFAULT_LIGHT_COLOR constants; adds phoneToWhatsAppDigits(raw, country) function to convert raw input to E.164 digits suitable for WhatsApp URLs; comprehensive test coverage for empty/undefined inputs, country-code prefixing, and fallback heuristics.
Label Component: Required Indicator Support
src/components/ui/Label/Label.tsx
Label component enhanced to accept children prop and optional required boolean flag; conditionally renders red asterisk * when required is true; replaces previous self-closing label pattern.
Form Fields: Required and Optional Labels
src/components/generator/BusinessShortCodeField/BusinessShortCodeField.tsx, src/components/generator/PhoneField/PhoneField.tsx, src/components/generator/MessageField/MessageField.tsx
BusinessShortCodeField and PhoneField now pass required prop to Label components; MessageField adds form.optional translation key and renders optional indicator alongside existing label.
GeneratorForm: Debounced URL Computation and Responsive Layout
src/components/generator/GeneratorForm/GeneratorForm.tsx
Introduces useDebouncedValue hook and URL_DEBOUNCE_MS constant to reduce URL computation frequency while typing; stores onChange callback in useRef to prevent effect re-runs on callback identity changes; refactors form layout from flex to responsive CSS grid with lg:grid-cols-2 and updates tracking section to span both columns.
GeneratorShell: FormValues State and Conditional Preview
src/components/generator/GeneratorShell/GeneratorShell.tsx
Refactors state management to store full FormValues | null instead of separate message string; computes derived flags (phoneFilled, shortCodeFilled, showPanel) based on variant requirements; conditionally renders PreviewPanel only when inputs satisfy variant requirements; message now sourced from values?.text.
PreviewPanel and QrPreview: Layout Refactoring and Color Customization
src/components/generator/PreviewPanel/PreviewPanel.tsx, src/components/generator/QrPreview/QrPreview.tsx
PreviewPanel restructured with conditional chat rendering based on non-empty message, responsive grid layout switching; QrPreview adds color state initialized from QR_DEFAULT_DARK_COLOR, new color picker control, and threads darkColor through canvas rendering, PNG and SVG downloads.

Layout, Navigation, and Internationalization

Layer / File(s) Summary
HomePage Skeleton and Navigation Links
src/app/[locale]/page.tsx, src/components/layout/Header/Header.tsx, src/components/layout/Footer/Footer.tsx
HomePage GeneratorFallback changed from grid to flex-column skeleton layout with first element height reduced from h-[30rem] to h-[24rem]; Header and Footer GitHub links updated from juliolmuller/openzap to LacusSolutions/open-zap.
Internationalization Updates: Form and Preview Labels
src/i18n/messages/en.json, src/i18n/messages/es.json, src/i18n/messages/pt-BR.json
All three language files updated: added form.optional key, changed preview title from "Preview"/"Vista previa"/"Pré-visualização" to "Result"/"Resultado"/"Resultado", added preview.qr.color key for color picker label.
Build and Repository Configuration
package.json, .github/CODEOWNERS
package.json lint script updated to reference eslint.config.mjs and vitest.config.mts; CODEOWNERS file assigns all files (*) to @LacusSolutions/engineering.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 A Fuzzy Refactor

Phone digits hop to WhatsApp's doorway,
Colors paint QRs in a brand-new hallway,
Forms debounce gently, labels shine bright,
Preview renders smart—conditional and light!
The shell stores values, the panel shows true,
English, Spanish, Portuguese—all in view! 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/layout-improvement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliolmuller

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot changed the title @coderabbitai Enhance WhatsApp generator with phone conversion and QR colors May 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/generator/GeneratorForm/GeneratorForm.tsx`:
- Around line 77-91: Wrap the call to phoneToWhatsAppDigits inside the useEffect
in a try-catch to guard against thrown errors or unexpected return values: when
variantRequiresPhone(v) is true, call
phoneToWhatsAppDigits(debouncedValues.phone, country) inside try, assign
phoneDigits on success and fall back to undefined on error, and ensure
buildWhatsAppUrl(...) and onChangeRef.current(url, debouncedValues) still run
with phone undefined (optionally log the caught error). This change touches the
useEffect block that references variantRequiresPhone, phoneToWhatsAppDigits,
buildWhatsAppUrl, and onChangeRef.

In `@src/components/generator/PreviewPanel/PreviewPanel.tsx`:
- Around line 54-58: Remove the redundant guard inside the onClick handler:
delete the conditional "if (!openable) return;" from the onClick anonymous
function so the handler simply calls onOpen?.() and window.open(url, '_blank',
'noopener,noreferrer'); rely on the existing disabled={!openable} prop to
prevent interaction; update the onClick in PreviewPanel to only reference onOpen
and url.

In `@src/components/ui/Label/Label.tsx`:
- Around line 17-21: Label currently renders the required asterisk with
aria-hidden="true", which makes the required state invisible to assistive tech;
update the Label component (the required prop handling) to expose semantics by
keeping the visual asterisk but also rendering screen-reader-visible text (e.g.,
a sr-only/visually-hidden <span> with the word "required") or by removing
aria-hidden and ensuring a sibling sr-only element exists, and document/ensure
consumers apply aria-required on the associated form control (or have Label
accept and forward an aria-required prop) so the required state is
programmatically exposed.

In `@src/lib/phone.test.ts`:
- Around line 1-31: Add extra unit tests to increase coverage for
phoneToWhatsAppDigits by creating cases for very short partial input (e.g.,
single or two digits like '9' or '12' with 'BR'), input that's exactly the
country calling code (e.g., '55' for BR, '1' for US), inputs mixing invalid
characters with digits (e.g., '(41' -> should strip to '5541'), and leading-zero
partials (e.g., '011' -> '5511'); add these new it(...) blocks to
src/lib/phone.test.ts alongside the existing tests so phoneToWhatsAppDigits
behavior for partial/edge inputs is explicitly asserted.
- Around line 24-30: The test is too permissive: update the test to assert exact
expected output (e.g., expect(phoneToWhatsAppDigits('415', 'US')).toBe('1415'))
so it fails with the current implementation, and then fix phoneToWhatsAppDigits
to correctly prepend the country calling code in its heuristic fallback path
(the logic currently relying on startsWith that returns "415" must produce
"1415" for country 'US'); locate and adjust the fallback branch in
phoneToWhatsAppDigits to explicitly prepend the country's DDI when the
parsed/partial national number does not already include it.

In `@src/lib/phone.ts`:
- Around line 65-76: The function phoneToWhatsAppDigits should treat inputs that
are only the country calling code (e.g., "+1" or "1") as "no phone number" and
return an empty string; after computing callingCode (from
getCountryCallingCode(country)) and digits (raw with non-digits stripped and
leading zeros removed) in phoneToWhatsAppDigits, add a check that if digits ===
callingCode or digits === `+${callingCode}` (accounting for possible formats)
then return '' before returning a value—this prevents returning a bare calling
code as a phone number while leaving existing parsed-number and normal
digit-prefix logic intact.
- Around line 54-76: The startsWith(callingCode) check in phoneToWhatsAppDigits
can mis-detect country code presence for short calling codes; update the final
branch to treat the digits as already containing the calling code only if they
start with callingCode AND are longer than just the calling code (i.e.
digits.startsWith(callingCode) && digits.length > callingCode.length), otherwise
prepend getCountryCallingCode(country); reference phoneToWhatsAppDigits, parsed,
callingCode, digits, and replace the existing startsWith logic with this
stricter prefix-length check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: da333dfb-8c5e-470f-9239-2b6a48a993e1

📥 Commits

Reviewing files that changed from the base of the PR and between 164e241 and 22ce954.

📒 Files selected for processing (20)
  • .github/CODEOWNERS
  • package.json
  • src/app/[locale]/page.tsx
  • src/components/generator/BusinessShortCodeField/BusinessShortCodeField.tsx
  • src/components/generator/GeneratorForm/GeneratorForm.tsx
  • src/components/generator/GeneratorShell/GeneratorShell.tsx
  • src/components/generator/MessageField/MessageField.tsx
  • src/components/generator/PhoneField/PhoneField.tsx
  • src/components/generator/PreviewPanel/PreviewPanel.tsx
  • src/components/generator/QrPreview/QrPreview.tsx
  • src/components/layout/Footer/Footer.tsx
  • src/components/layout/Header/Header.tsx
  • src/components/ui/Label/Label.tsx
  • src/i18n/messages/en.json
  • src/i18n/messages/es.json
  • src/i18n/messages/pt-BR.json
  • src/lib/phone.test.ts
  • src/lib/phone.ts
  • src/lib/qrcode.ts
  • vitest.config.mts

Comment thread src/components/generator/GeneratorForm/GeneratorForm.tsx
Comment thread src/components/generator/PreviewPanel/PreviewPanel.tsx
Comment thread src/components/ui/Label/Label.tsx Outdated
Comment thread src/lib/phone.test.ts
Comment thread src/lib/phone.test.ts Outdated
Comment thread src/lib/phone.ts
Comment thread src/lib/phone.ts
juliolmuller and others added 2 commits May 12, 2026 15:16
Adjustment as perCodeRabbit AI review comment at #1 (comment).

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adjustment as per CodeRabbit AI review comment at #1 (comment).

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
@juliolmuller

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ui/Label/Label.tsx`:
- Line 22: The fallback 'required' string causes hardcoded English for screen
readers; update the Label component to avoid this by either (A) making
requiredAnnouncement mandatory when required is true via a conditional prop type
(e.g., change LabelProps so requiredAnnouncement is required if required ===
true) or (B) add a development-only runtime check inside the Label function that
detects if required && !requiredAnnouncement and emits a console.warn (and keep
announced as before) so callers are alerted; reference the announced variable
and the requiredAnnouncement/required props when implementing the chosen fix.

In `@src/lib/phone.test.ts`:
- Around line 24-45: Add a regression test to ensure explicit international
partial input like "+55 11" is handled correctly: add an assertion calling
phoneToWhatsAppDigits('+55 11', 'BR') and expect '5511'. Locate the test suite
that contains the other partial-input cases (the tests around
phoneToWhatsAppDigits) and add this new spec alongside those cases so the
function's normalization of '+' and whitespace for DDI prefixes is locked in.

In `@src/lib/phone.ts`:
- Around line 85-88: The fallback currently always returns
`${callingCode}${digits}`, which double-prefixes when the raw input was
explicitly international (e.g., started with '+' or '00') and the sanitized
digits already begin with the callingCode; update the logic in the function
around parsePhoneNumberFromString/intlParsed so that if the original raw input
contains an explicit international prefix ('+' or leading '00') and
digits.startsWith(callingCode) you return digits (or digits without any leading
'+') directly instead of prepending callingCode—otherwise keep the existing
fallback behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4b8d0f1b-d2e2-4bb6-b43e-55dc9932561d

📥 Commits

Reviewing files that changed from the base of the PR and between 22ce954 and 1bf35c4.

📒 Files selected for processing (8)
  • src/components/generator/BusinessShortCodeField/BusinessShortCodeField.tsx
  • src/components/generator/PhoneField/PhoneField.tsx
  • src/components/ui/Label/Label.tsx
  • src/i18n/messages/en.json
  • src/i18n/messages/es.json
  • src/i18n/messages/pt-BR.json
  • src/lib/phone.test.ts
  • src/lib/phone.ts

Comment thread src/components/ui/Label/Label.tsx Outdated
Comment thread src/lib/phone.test.ts
Comment thread src/lib/phone.ts
juliolmuller and others added 3 commits May 12, 2026 16:01
Fix as per CodeRabbit AI review comment at #1 (comment).

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adjustment as per CodeRabbit AI review comment at #1 (comment).

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@juliolmuller juliolmuller merged commit 9b1a65f into main May 12, 2026
2 of 3 checks passed
@juliolmuller juliolmuller deleted the feat/layout-improvement branch May 12, 2026 19:14
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.1.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released Automation related to releases runs. label May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New minor or major features. released Automation related to releases runs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant