Commit Graph

57 Commits

Author SHA1 Message Date
tanweer919 a459fefb7f feat(landing): port the full marketing site into the CRM (static)
Copies the goutam-pages landing (React marketing home + /page/1..19 + assets)
into /public and adds beforeFiles rewrites so '/' serves the marketing home and
'/1'..'/19' + '/thanks' serve the static pages — reproducing the landing's
vercel.json clean URLs. /portal/* (login/register) is untouched.
2026-07-18 00:06:53 +05:30
tanweer919 f634312b83 feat(profile): wire Profile to the be-crm profile data door
New src/lib/profile-api.ts (useProfileData) mirrors team-api: live (crm.account/
kyc/notifications/consent) or local mock, one interface. profile.tsx consumes it —
Personal (verify-to-reveal + change contact OTP), KYC (real file upload/remove),
Notifications (matrix, timezone, windows, add/verify destination), Privacy (consent).
Security + Devices stay on the mock (Shell-owned).
2026-07-15 18:57:39 +05:30
tanweer919 9eb234935d refactor(email): remove frontend invite email; be-crm sends it now
Per AppShell, email delivery lives in the domain API. Delete the frontend
/api/email/invite route + invite-email template, and the team-management email
wiring. be-crm now emails invitees on create/resend. Copy link stays as a
fallback (invite token still returned in the pending-invite list).
2026-07-14 15:38:53 +05:30
tanweer919 1a2043eaae fix(login): readable email-OTP send error instead of raw '{}'
gotrue can throw an error whose message is an unhelpful JSON blob (e.g. 500
'Error sending magic link email' when Supabase SMTP isn't configured). Show a
readable, actionable message instead of rendering the raw payload.
2026-07-13 20:44:05 +05:30
tanweer919 eeded95940 fix(team): show member real name + email (no more principal UUIDs)
Use displayName + email now returned by be-crm member search (from CRM
registration). Falls back to the ACE for the current user, then job title —
never the raw principal id as the email.
2026-07-13 20:33:01 +05:30
tanweer919 be4bd5f41d fix(invite): look up the invitation and route correctly (register vs sign in)
The invite link is token-only, so the landing page couldn't tell the invited
email or whether an account existed — it dumped everyone on an empty register
screen. Now it calls a public lookup (/api/invite/lookup → be-crm) and:
- first-time invitee → register with the email prefilled + locked;
- email already registered → sign in with the email prefilled;
- signed-in + registered → accept immediately; signed-in + no profile → onboarding.
Login now redeems the pending invite after sign-in (password/OTP/OAuth), so an
existing user's invite is accepted on login (not only when already logged in).
2026-07-13 20:25:25 +05:30
tanweer919 cc71516278 feat(email): send team invitations from a Vercel serverless route (Twilio)
- POST /api/email/invite: sends the invite email via the Twilio Emails API using
  server-only TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN (Vercel env), from
  EMAIL_FROM_ADDRESS (default support@lynkedup.dev). Fixed invite template; gated
  on a session cookie so it isn't an open relay.
- Team Management emails the invite on create and resend (token now returned by
  both), with the Copy-link as a fallback. Mock mode skips email.
2026-07-13 19:48:19 +05:30
tanweer919 103f3ae3a1 feat(rbac): no role at registration; invitation-based membership; nav gating
- Registration no longer asks for a role/persona (removed the role select +
  allottee block); crm.account.register sends no persona.
- New users have no permissions → the sidebar now shows only Dashboard + Profile
  for them, gated on crm.account.me (membership + permissions). Members see the
  areas their permissions allow.
- Add /portal/invite?token=… : accepts the invite for a signed-in registered
  user, or routes an unregistered invitee through register/onboarding, which
  redeems the stashed token on completion (granting the invited role).
- Team Management: 'Copy link' on pending invites builds the invite link from
  the invitation token (no email delivery yet).
2026-07-13 16:25:53 +05:30
tanweer919 68bf137d11 fix(legal): explicit spacing after inline elements on SMS opt-in page 2026-07-13 14:59:59 +05:30
tanweer919 5f67c8fa85 fix(legal): correct spacing around company name on opt-in and terms pages 2026-07-13 14:55:33 +05:30
tanweer919 5511ef4110 feat(legal): SMS opt-in form + Privacy Policy + Terms for Twilio A2P 10DLC
Public, unauthenticated pages required for A2P 10DLC campaign verification:
- /sms-opt-in: web opt-in form (phone field, un-pre-checked consent checkbox,
  message description, frequency, msg&data-rates + HELP/STOP disclaimers, links
  to Terms & Privacy, 'Yes, sign me up!' submit).
- /privacy: Privacy Policy with the mandatory SMS clauses (no third-party/affiliate
  sharing of mobile numbers or SMS consent, message frequency, rates disclosure).
- /terms: Terms of Service with an SMS program-terms section.
Business details centralized in legal-config.ts (replace SMS_SENDER with the
live Twilio number once approved).
2026-07-13 14:50:49 +05:30
tanweer919 127e0f8912 fix(login): back-button nav, single OTP channel, register back buttons
- Login: identify → password/otp now push() history (was replace()), so Back
  returns to the email screen instead of leaving to /register.
- Login: in Shell mode the OTP screen no longer shows an email/SMS toggle —
  the channel is fixed by how you signed in, so email sign-in never shows a
  stray SMS option.
- Login: hide phone (SMS) sign-in while OTP is mocked — a faked login code
  can't mint a session (AuthGate would bounce), so it can't work without SMS.
  Email OTP + password + Google stay real and working.
- Register: add Back buttons (email screen → sign in; profile screen → email).
- Share MOCK_OTP/DEMO_OTP via @/lib/otp.
2026-07-13 14:32:18 +05:30
tanweer919 27a5aa939e feat(otp): mock phone OTP fallback while Twilio SMS is down
The Twilio sender isn't delivering, so gate the Verify step behind
NEXT_PUBLIC_MOCK_OTP (default true): 'Send code' skips Supabase/Twilio and a
fixed demo code (123456) verifies, with clear demo-mode copy. The real
addPhone/verifyPhone path is untouched — flip the flag to "false" to restore
live SMS verification.
2026-07-13 13:59:04 +05:30
tanweer919 da7f7a7891 feat(register/onboard): real phone OTP verification via Twilio (SDK 0.2.6)
Replaces the mock verify step (which accepted any 6 digits) with a real SMS
OTP: addPhone() → Supabase/Twilio texts a code → verifyPhone() confirms it.

- Registration creates the auth account when leaving the Account step, so the
  phone can be attached + verified against a live Supabase session; finish()
  no longer double-registers.
- Onboarding gains a real phone-verify step (Profile → Verify → Address).
- Email is trusted without an OTP in both flows (Supabase auto-confirms on
  signup; Google verifies for onboarding), matching project config.
- Bump @abe-kap/appshell-sdk to ^0.2.6.
2026-07-13 04:29:02 +05:30
tanweer919 3c6190d16a Merge pull request 'fix(onboarding): reliably prefill verified email (SDK 0.2.5)' (#15) from tanweer919/lynkeduppro-crm:feat/login-methods into goutamnextflow 2026-07-12 22:36:29 +00:00
tanweer919 6ba00bfbf9 fix(onboarding): reliably prefill the verified email (SDK 0.2.5)
getUserEmail() relied on getSession(), which returns null here because the
Supabase session is intentionally never persisted to storage — so the
onboarding email field stayed empty and Continue was blocked. SDK 0.2.5
captures the email in memory from the token-exchange response instead.
Bump @abe-kap/appshell-sdk to ^0.2.5.
2026-07-13 04:06:13 +05:30
tanweer919 5e2fa574bd Merge pull request 'fix(onboarding): gate direct access behind OAuth handoff' (#14) from tanweer919/lynkeduppro-crm:feat/login-methods into goutamnextflow 2026-07-12 22:32:35 +00:00
tanweer919 d79da8cd6a fix(onboarding): gate direct access behind the OAuth handoff
/portal/onboarding is only a step in the Google sign-in flow. Redirect to
login unless the login page's onboard_email handoff hint is present (and the
session is authenticated), instead of showing an empty form on direct/typed
URL access. Hold rendering until the check passes to avoid a form flash, and
clear the hint once onboarding completes so it can't be reused.
2026-07-13 04:01:01 +05:30
tanweer919 10141806dc Merge pull request 'fix(onboarding): prefill verified email; SDK 0.2.4' (#13) from tanweer919/lynkeduppro-crm:feat/login-methods into goutamnextflow 2026-07-12 22:26:05 +00:00
tanweer919 08ef85869f fix(onboarding): prefill verified email in a disabled field; bump SDK 0.2.4
- Onboarding reads the OAuth email (session-storage hint + live Supabase
  session via getUserEmail) so Continue is no longer disabled.
- Replace the empty 'Signed in as' banner with a disabled, prefilled
  email field (email is fixed — Google-verified).
- Stash the verified email at OAuth callback time for onboarding prefill.
- Bump @abe-kap/appshell-sdk to ^0.2.4 (getUserEmail via getSession).
2026-07-13 03:55:05 +05:30
tanweer919 619ec4c9b1 Merge pull request 'feat(auth): Google onboarding flow (option 3)' (#12) from feat/login-methods into goutamnextflow 2026-07-12 22:06:03 +00:00
tanweer919 948abf75fd feat(auth): first-time Google onboarding (option 3)
After a Google sign-in with no CRM profile, route to /portal/onboarding — the
registration flow in mode='onboard': email skipped (Google-verified, prefilled
via getUserEmail), sets a password (updateUser) so email+password login also
works, skips the OTP-verify step, and persists the profile via crm.account.register.
Existing-profile users go straight to the dashboard. Bumps SDK ^0.2.3.
2026-07-13 03:35:55 +05:30
tanweer919 66cd8953ba Merge pull request 'feat(auth): gate Google sign-in on CRM profile' (#11) from feat/login-methods into goutamnextflow 2026-07-12 21:52:11 +00:00
tanweer919 34cb44cfa8 feat(auth): gate Google sign-in on an existing CRM profile
Google is sign-IN only: after OAuth, check crm.account.registrationStatus; if the
account has no CRM profile, sign back out and show an error on the login screen
instead of admitting a profile-less user. (Onboarding to collect the profile comes later.)
2026-07-13 03:22:04 +05:30
tanweer919 11931cbf6f Merge pull request 'polish: real role in user chip' (#10) from feat/login-methods into goutamnextflow 2026-07-12 21:33:24 +00:00
tanweer919 f38fa80bde polish(dashboard): show real ACE role in user chip instead of static 'Property Owner' 2026-07-13 03:03:17 +05:30
tanweer919 43f9a3eb83 Merge pull request 'feat(dashboard): real user + sign-out; remove demo text' (#9) from feat/login-methods into goutamnextflow 2026-07-12 21:27:58 +00:00
tanweer919 86af77c92b feat(dashboard): real user in sidebar + sign-out; strip demo/mock hints
- Sidebar footer now shows the ACE identity (was static 'James Carter') with a
  Sign-out menu; topbar user gets a Sign-out dropdown too. Both call useAuth().logout.
- Remove all visible 'Demo:' hints from login + register and the 'Demo mode' subtitle.
2026-07-13 02:57:51 +05:30
tanweer919 f5ff7bf6ea Merge pull request 'fix(auth): session persists on reload (SDK 0.2.2)' (#8) from feat/login-methods into goutamnextflow 2026-07-12 21:11:46 +00:00
tanweer919 27e7bdf8f5 fix(auth): bump appshell-sdk 0.2.2 (ready-after-restore) — session persists on reload 2026-07-13 02:41:39 +05:30
tanweer919 3e79b3bf31 Merge pull request 'fix(auth): session persists on reload (gate redirect on boot-ready)' (#7) from feat/login-methods into goutamnextflow 2026-07-12 21:05:20 +00:00
tanweer919 64be4b9b3f fix(auth): don't redirect from dashboard until SDK boot completes
AuthGate redirected to /portal/login whenever status !== authenticated, which
during boot (before restore() resolves) dropped a valid session on reload. Gate
the redirect on useAppShell().ready so we only bounce once auth has resolved.
2026-07-13 02:35:13 +05:30
tanweer919 e08fa357f7 Merge pull request 'chore: remove debug logging' (#6) from feat/login-methods into goutamnextflow 2026-07-12 20:47:30 +00:00
tanweer919 5186497c50 chore(auth): remove debug logging from OAuth + registration error paths 2026-07-13 02:17:22 +05:30
tanweer919 e37ef375eb Merge pull request 'fix(auth): PKCE verifier (SDK 0.2.1) — Google sign-in' (#5) from feat/login-methods into goutamnextflow 2026-07-12 20:32:32 +00:00
tanweer919 0e8a207640 fix(auth): bump appshell-sdk 0.2.1 (PKCE verifier fix); tidy OAuth error handling 2026-07-13 02:02:24 +05:30
tanweer919 66118ff63f Merge pull request 'fix(auth): surface OAuth error' (#4) from feat/login-methods into goutamnextflow 2026-07-12 20:15:17 +00:00
tanweer919 7570fe7be3 fix(auth): surface the real OAuth completion error (console + flash) 2026-07-13 01:45:10 +05:30
tanweer919 6d0c8890d3 Merge pull request 'fix(auth): complete Google OAuth after SDK boot' (#3) from feat/login-methods into goutamnextflow 2026-07-12 20:01:53 +00:00
tanweer919 6e1a895e7e fix(auth): complete Google OAuth after SDK boot (was stuck on ?code=…#identify)
The OAuth-return effect ran on mount before AppShell finished booting, so
completeOAuthLogin no-oped (sdk.auth undefined → null) and fell back to identify,
never retrying. Gate it on useAppShell().ready so it runs once auth is up, and
strip ?code= from the URL on success.
2026-07-13 01:31:37 +05:30
tanweer919 e9ec33d412 Merge pull request 'feat(auth): Google-only social; email/password sign-up; phone login' (#2) from feat/login-methods into goutamnextflow 2026-07-11 15:19:06 +00:00
tanweer919 74caae0710 feat(auth): Google-only social; sign-up email/password only; phone login entry
- SocialButtons: only Google (Microsoft/Apple hidden).
- Sign-up: remove all social (email/password only).
- Login: keep Google + email/password (single step) + email/SMS OTP; add a direct
  'Sign in with a phone number' entry (SMS OTP), and rename the OTP link to
  'Sign in with a one-time code'. All Supabase-supported; no mandatory 2FA.
2026-07-11 20:48:47 +05:30
tanweer919 2a653b807b Merge pull request 'feat: AppShell integration — auth, email/SMS OTP login, live multi-role team management' (#1) from tanweer919/lynkeduppro-crm:feat/appshell-integration into goutamnextflow 2026-07-11 14:24:59 +00:00
tanweer919 339e2b007a feat(register): persist full registration to crm.account.register
Lift StepAddress/AddressBlock state up so finish() can send the complete
sign-up payload (name, phone, persona, allottee id/names, registered+mailing
address, consent) to be-crm crm.account.register after auth. Config-gated;
non-fatal if the domain persist fails (auth account already created).
2026-07-11 06:19:49 +05:30
tanweer919 565019a75c feat(team+auth): live multi-role team management + email/SMS OTP login
- team-management: new useTeamData() data layer serves live be-crm data door
  (crm.team.member.search/role.list/invitation.list + set-roles/perm/invite
  commands) or the mock fallback, gated on isShellConfigured(). A member can
  hold MANY roles: role chips + multi-select picker in Edit/Invite modals.
- login OTP: OtpVerify wired to real Supabase email + SMS OTP (passwordless)
  via appshell sendEmailOtp/verifyEmailOtp + sendPhoneOtp/verifyPhoneOtp.
- bump @abe-kap/appshell-sdk ^0.2.0 (phone OTP).
2026-07-11 04:44:54 +05:30
tanweer919 1d37593102 feat(appshell): integrate @abe-kap/appshell-sdk (strangler, mock fallback)
Wire the AppShell SDK for auth/identity across the CRM, gated behind
isShellConfigured() so the existing mock portal + static demo user stay
the fallback until the Shell BFF is configured.

- providers.tsx: app-wide <AppShellProvider> (auth passed only when Supabase env set)
- next.config.ts: transpilePackages + /shell -> BFF rewrite (keeps /api/geo intact)
- login: password -> login(), social -> loginWithOAuth(), OAuth return -> completeOAuthLogin()
- register: email/password sign-ups call register() on finish
- dashboard: AuthGate bounces unauthenticated visitors; topbar shows ACE identity
- docs/APPSHELL_INTEGRATION.md, .env.local.example, .npmrc for GitHub Packages
2026-07-09 20:51:17 +05:30
Goutam0612 9675bf014d Sidebar light-theme fix; remove Property step from registration
- dashboard sidebar now uses the --sidebar token so it turns white in
  light mode instead of staying black; active nav item stays readable
- registration: drop the Property / Job ID step (job ID + find-by-address),
  flow is now Account -> Verify -> Address with steps renumbered

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:39:03 +05:30
Goutam 25420bef8e Team roles: construction personas with attire notes; fix dark-theme dropdown
- Replace roles with the 10 Construction Industry personas (Owner, Admin,
  Sales Manager, Sales Rep, Project Manager, Site Supervisor, Canvasser,
  Team Lead, Subcontractor, Other), each with description, attire &
  appearance cues and a common-overlap note
- Render Attire & appearance + Common overlap sections on each role card
- Remap members/invites to new role ids; add canvasser, team-lead and
  subcontractor members so every persona shows
- Set color-scheme per theme and style <select> options so the role
  dropdown is legible in dark mode

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 16:39:14 +05:30
Goutam f1a7bdc8ce Role-aware registration: Customer/Employee/Owner/Contractor/Sub-Con/Vendor
- New "Your role" options matching the portal roles
- Customer/Owner = self; Employee shows an Employee ID field;
  Contractor/Sub-Con/Vendor show their ID + property owner name
- Validation adapts per role

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:14:12 +05:30
Goutam b79d925552 Show real flag image in registration phone field
Flag emojis don't render on Windows, so derive an ISO code from the
emoji's regional indicators and load a flagcdn image in front of the
country-code selector (Account + Verify steps).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:00:37 +05:30