diff --git a/stripe_to_invoice/README.md b/stripe_to_invoice/README.md index f60e569..6ccf291 100644 --- a/stripe_to_invoice/README.md +++ b/stripe_to_invoice/README.md @@ -41,25 +41,43 @@ Got you — here’s a clean, founder-brain-friendly summary of **Stripe → Inv --- -## ⚠️ Known issues you’ve already identified +## ✅ Recently fixed -* Xero contact creation: +* **Xero contact creation** — Now checks for existing contacts by email first, reuses if found, only creates if missing +* **Stripe OAuth app reuse** — Added unique constraints on `userId` and `stripeAccountId` to prevent duplicate connections +* **Smart redirect flow** — Users are automatically routed based on connection state: + * Both connected → `/dashboard` + * Only Stripe → `/connect/xero` + * No connections → `/connect/stripe` +* **Connection visibility** — Dashboard now displays connected Stripe account ID and Xero tenant ID - * Need to **check for existing contact by email first** (currently can fail automation) -* Stripe OAuth: +### Frontend Improvements Details + +**Smart Onboarding Flow** +* Automatic routing based on connection state +* Users never see unnecessary steps +* Seamless progression: Login → Stripe → Xero → Dashboard + +**Dashboard Enhancements** +* Connected account visibility (Stripe account ID + Xero tenant) +* Account code configuration (sales + clearing accounts) +* Real-time save confirmation +* Clean, minimal UI + +**Development Experience** +* Development mode fallback for webhook testing +* Comprehensive logging at each webhook stage +* Environment-aware configuration + +--- + +## ⚠️ Known issues - * Currently creates a **new Stripe app every time** instead of reusing → needs fixing * Account codes: - * Default behaviour needed on first Xero connection: - - * `salesAccountCode = 200` - * `stripeClearingAccountCode = 610` - * Future: auto-detect or create a proper “Stripe Clearing” account and store it * Missing UX guardrails: * No clear **pre-payment checklist** before enabling sync - * No UI yet to review/change account codes (fine for v1, but coming) --- @@ -81,15 +99,11 @@ Got you — here’s a clean, founder-brain-friendly summary of **Stripe → Inv These unlock charging real money. -* [ ] Fix Xero contact creation: +* [x] ~~Fix Xero contact creation~~ ✅ DONE - * Check by email → reuse if exists → only create if missing -* [ ] Fix Stripe OAuth app reuse (stop creating new apps) -* [ ] Ensure default Xero account codes are set **on first connection** - - * sales = 200 - * clearing = 610 -* [ ] Re-enable “mark invoice as paid” via Stripe Clearing once accounts are valid + * ~~Check by email → reuse if exists → only create if missing~~ +* [x] ~~Fix Stripe OAuth app reuse (stop creating new apps)~~ ✅ DONE +* [x] ~~Re-enable "mark invoice as paid" via Stripe Clearing once accounts are valid~~ ✅ DONE > Outcome: rock-solid, boring, accountant-approved flow @@ -97,18 +111,30 @@ These unlock charging real money. ### 2️⃣ Add a tiny **pre-flight checklist UI** (not a full settings page) -* One screen before enabling sync: +* [x] ~~Dashboard shows connected accounts~~ ✅ DONE - * ✔ Stripe connected - * ✔ Xero connected - * ✔ VAT status detected - * ✔ Sales account code shown (read-only for now) - * ✔ Stripe clearing account shown -* Even if it’s ugly — this prevents 80% of future support pain + * ~~Stripe account ID displayed~~ + * ~~Xero tenant ID displayed~~ +* [x] ~~Smart redirect flow based on connection state~~ ✅ DONE +* [ ] VAT status detection +* [ ] Sales account code shown (editable) +* [ ] Stripe clearing account shown (editable) + +> Even basic connection visibility prevents 80% of future support pain --- -### 3️⃣ Switch from “design partner” → **first paid customer mode** +### 3️⃣ Implement subscription billing (enables first paid customer) + +* Integrate Stripe Billing for subscription management +* Add usage tracking (invoice count per month) +* Create pricing page and checkout flow +* Implement subscription status checks in webhook handler +* Remove "internal test" banner once billing is live + +--- + +### 4️⃣ Switch from "design partner" → **first paid customer mode** * Pick **one**: @@ -116,16 +142,16 @@ These unlock charging real money. * A cold UK Stripe + Xero business with obvious VAT needs * Offer: - * £10–£30/month - * “Early access / founder pricing” + * £15/month Starter plan + * "Early access / founder pricing" (50% off for life) * Manual support included * Goal is **money changing hands**, not scale -> You’ve said it yourself: getting paid energises you — lean into that. +> You've said it yourself: getting paid energises you — lean into that. --- -### 4️⃣ Do *targeted* cold outreach (low volume, high signal) +### 5️⃣ Do *targeted* cold outreach (low volume, high signal) * 5–10 emails max, not a campaign * Target: @@ -135,21 +161,81 @@ These unlock charging real money. * Clearly VAT-registered * Lead with: - * “I built this because my accountant hated existing tools” + * "I built this because my accountant hated existing tools" * Emphasise **audit-safe, VAT-correct invoices** - * Not “automation”, not “syncing” + * Not "automation", not "syncing" --- -### 5️⃣ Only then: small UX polish + automation +### 6️⃣ Future UX polish + automation (after first paying customers) -* UI to review/change account codes -* Auto-detect or create Stripe Clearing account +* Auto-detect or create Stripe Clearing account in Xero +* Bulk historical invoice sync +* Invoice preview before creation * Reduce manual fixes you find yourself repeating * Nothing else until: * You have **~3–5 paying users** - * And they’re still using it after month 1 + * And they're still using it after month 1 + +--- + +## 💳 SaaS Subscription Model (proposed) + +### Pricing Tiers + +**Starter — £15/month** +* Up to 50 invoices/month +* Stripe Payment Links + one-off payments +* Email support (48h response) +* Perfect for: Solo founders, side projects, small consultancies + +**Professional — £35/month** +* Up to 200 invoices/month +* Everything in Starter, plus: + * Stripe Subscriptions support + * Priority email support (24h response) + * Custom account code mapping +* Perfect for: Growing businesses, SaaS products, agencies + +**Business — £75/month** +* Unlimited invoices +* Everything in Professional, plus: + * Multi-currency support (planned) + * Dedicated Slack support + * Early access to new features +* Perfect for: Established businesses, high-volume merchants + +### Implementation Notes + +* **Billing via Stripe Checkout** (dogfooding our own product) +* **Monthly recurring subscriptions** with automatic renewal +* **14-day free trial** — no credit card required +* **Founder pricing lock-in** — First 50 customers get lifetime 50% off +* **Usage tracking** — Invoice count displayed in dashboard, soft warnings at 80% of limit +* **Graceful degradation** — Over-limit users get notified but sync continues (no hard cutoff) + +### Revenue Model + +* **Target: 100 paying customers in 6 months** + * 60% Starter (£900/mo) + * 30% Professional (£1,050/mo) + * 10% Business (£750/mo) + * Total: ~£2,700/mo MRR + +* **Conservative burn** + * Hosting: £50/mo (Vercel + DB) + * Email: £10/mo (AWS SES) + * Support: Founder time only + * Net: ~£2,640/mo profit margin + +### Next Steps for Monetization + +1. Add Stripe Billing integration to the app +2. Implement usage tracking in webhook handler +3. Create pricing page on landing site +4. Add subscription management in dashboard +5. Enable payments and remove "internal test" banner --- diff --git a/stripe_to_invoice/app/app/page.tsx b/stripe_to_invoice/app/app/page.tsx index 5d118fc..bc74d16 100644 --- a/stripe_to_invoice/app/app/page.tsx +++ b/stripe_to_invoice/app/app/page.tsx @@ -1,4 +1,3 @@ -// app/app/page.tsx import { redirect } from "next/navigation"; import Link from "next/link"; import { eq } from "drizzle-orm"; @@ -14,65 +13,119 @@ export default async function AppPage() { redirect("/login"); } - // Check if user has Stripe connection const stripeConn = await db .select() .from(stripeAccounts) .where(eq(stripeAccounts.userId, user.id)) .limit(1); - // Check if user has Xero connection const xeroConn = await db .select() .from(xeroConnections) .where(eq(xeroConnections.userId, user.id)) .limit(1); - // If both connected, go to dashboard if (stripeConn.length > 0 && xeroConn.length > 0) { redirect("/dashboard"); } - // If only Stripe connected, go to Xero connection if (stripeConn.length > 0 && xeroConn.length === 0) { redirect("/connect/xero"); } - // Otherwise, show Stripe connection step return ( -
-

- Welcome{user.email ? `, ${user.email}` : ""} -

+
+ {/* Navigation */} + - {/* Progress */} -
    -
  1. - - - Logged in as {user.email} - -
  2. +
    +
    + {/* Welcome Section */} +
    +

    + Welcome, {user.email?.split("@")[0]}! 👋 +

    +

    + Let's set up your Stripe to Xero automation in just two steps. +

    +
    -
  3. - - Connect Stripe -
  4. + {/* Progress Visualization */} +
    +

    Setup progress

    -
  5. - Xero will be connected after Stripe -
  6. -
+
+ {/* Step 1 - Login */} +
+
+
+ + + +
+
+
+
+

Email verified

+

{user.email}

+
+
- {/* Primary CTA */} -
- - Connect Stripe - -
-
+ {/* Step 2 - Stripe */} +
+
+
+ 2 +
+
+
+
+

Connect Stripe

+

Link your Stripe account to detect payments

+
+
+ + {/* Step 3 - Xero */} +
+
+
+ 3 +
+
+
+

Connect Xero

+

Link your Xero organisation to create invoices

+
+
+ + + + {/* CTA Section */} +
+

+ Ready to automate? +

+

+ Connect your Stripe account to start detecting payments. You'll connect Xero next. +

+ + Connect Stripe → + +
+ + + ); } diff --git a/stripe_to_invoice/app/auth/callback/AuthCallbackClient.tsx b/stripe_to_invoice/app/auth/callback/AuthCallbackClient.tsx index b8cc1ea..9c110f9 100644 --- a/stripe_to_invoice/app/auth/callback/AuthCallbackClient.tsx +++ b/stripe_to_invoice/app/auth/callback/AuthCallbackClient.tsx @@ -33,8 +33,35 @@ export default function AuthCallbackClient() { }, [params, router]); return ( -
-

Signing you in…

-
+
+
+ {/* Animated loader */} +
+
+
+
+
+
+
+
+ + {/* Text */} +

Signing you in…

+

+ Please wait while we authenticate your account +

+ + {/* Progress indication */} +
+
+
+ + + +
+
+
+
+
); } diff --git a/stripe_to_invoice/app/connect/stripe/page.tsx b/stripe_to_invoice/app/connect/stripe/page.tsx index cbce634..5d71008 100644 --- a/stripe_to_invoice/app/connect/stripe/page.tsx +++ b/stripe_to_invoice/app/connect/stripe/page.tsx @@ -1,11 +1,3 @@ -// app/connect/stripe/page.tsx -// -// STEP 2 — Connect Stripe -// Purpose: -// - Explain why Stripe access is needed -// - Provide a single, clear action -// - Feel safe, boring, and familiar (Zapier-style) - import { cookies } from "next/headers"; import { redirect } from "next/navigation"; @@ -13,65 +5,132 @@ export default async function ConnectStripePage() { const cookieStore = await cookies(); const session = cookieStore.get("session"); - // Safety: if not logged in, bounce to login if (!session) { redirect("/login"); } return ( -
- {/* -------------------------------------------------- - Header - -------------------------------------------------- */} -
-

- Connect Stripe -

+
+ {/* Navigation */} + -

- We need read-only access to your Stripe account so we can - detect successful payments and automatically reconcile - invoices in Xero. -

-
+
+
+ {/* Header */} +
+
+ + Step 2 of 3 +
- {/* -------------------------------------------------- - What will happen - -------------------------------------------------- */} -
-

- What happens next -

+

+ Connect Stripe +

-
    -
  • You’ll be redirected to Stripe
  • -
  • You’ll choose which Stripe account to connect
  • -
  • You’ll be sent back here once connected
  • -
-
+

+ We need read-only access to your Stripe account to monitor successful payments and automatically create invoices in Xero. +

+
- {/* -------------------------------------------------- - Trust / reassurance - -------------------------------------------------- */} -
-

- We never see your passwords. -
- Access can be revoked at any time from Stripe. -

-
+ {/* Two Column Layout */} +
+ {/* Left Column - Information */} +
+ {/* What we access */} +
+

What we can access

+
    +
  • + + + +
    +

    Payment events

    +

    Successful charges and refunds

    +
    +
  • +
  • + + + +
    +

    Account information

    +

    Your account ID and basic metadata

    +
    +
  • +
+
- {/* -------------------------------------------------- - Primary action - -------------------------------------------------- */} -
- - Connect Stripe → - -
-
+ {/* What we cannot do */} +
+

What we cannot do

+ +
+ + {/* How it works */} +
+

What happens next

+
    +
  1. + 1 + You'll be securely redirected to Stripe +
  2. +
  3. + 2 + Select which Stripe account to connect +
  4. +
  5. + 3 + You'll be returned here to connect Xero +
  6. +
+
+ + + {/* Right Column - CTA Card */} +
+
+

Ready?

+ + Connect Stripe → + +

+ You'll be redirected to Stripe's secure OAuth page +

+
+
+ + + {/* Trust badges */} +
+

+ 🔒 Your security matters: We use OAuth, so you can revoke access from Stripe at any time. We never see or store your Stripe password. +

+
+ +
+ ); } diff --git a/stripe_to_invoice/app/connect/stripe/success/page.tsx b/stripe_to_invoice/app/connect/stripe/success/page.tsx index 85efe16..84e9ace 100644 --- a/stripe_to_invoice/app/connect/stripe/success/page.tsx +++ b/stripe_to_invoice/app/connect/stripe/success/page.tsx @@ -2,43 +2,104 @@ import Link from "next/link"; export default function StripeSuccessPage() { return ( -
-

- Stripe connected 🎉 -

+
+ {/* Navigation */} + -

- Your Stripe account is now linked. We can now detect successful - payments and automatically reconcile invoices in Xero. -

+
+
+ {/* Success Animation */} +
+
+ + + +
- {/* Progress */} -
    -
  1. - - Logged in -
  2. +

    + Stripe connected! 🎉 +

    -
  3. - - Stripe connected -
  4. +

    + Your Stripe account is now securely linked. We can detect successful payments and automatically reconcile invoices in Xero. +

    +
-
  • - - Connect Xero -
  • - + {/* Progress Card */} +
    +

    Setup progress

    - {/* Primary CTA */} -
    - - Continue → Connect Xero - -
    -
    +
    + {/* Step 1 - Login */} +
    +
    +
    + + + +
    +
    +
    +
    +

    Email verified

    +

    Authentication complete

    +
    +
    + + {/* Step 2 - Stripe */} +
    +
    +
    + + + +
    +
    +
    +
    +

    Stripe connected

    +

    Payment monitoring active

    +
    +
    + + {/* Step 3 - Xero */} +
    +
    +
    + 3 +
    +
    +
    +

    Connect Xero

    +

    One final step to enable automation

    +
    +
    +
    +
    + + {/* CTA */} +
    +

    + Ready for the final step? +

    +

    + Now connect your Xero organisation to complete the setup and start automating invoices. +

    + + Continue to Xero → + +
    + +
    + ); } diff --git a/stripe_to_invoice/app/connect/xero/page.tsx b/stripe_to_invoice/app/connect/xero/page.tsx index 30afae5..f4bf605 100644 --- a/stripe_to_invoice/app/connect/xero/page.tsx +++ b/stripe_to_invoice/app/connect/xero/page.tsx @@ -1,9 +1,3 @@ -// STEP 3 — Connect Xero -// Purpose: -// - Explain why Xero access is needed -// - Make the next step obvious -// - Match the Stripe connect page exactly - import { cookies } from "next/headers"; import { redirect } from "next/navigation"; @@ -11,64 +5,141 @@ export default async function ConnectXeroPage() { const cookieStore = await cookies(); const session = cookieStore.get("session"); - // Safety: if not logged in, bounce to login if (!session) { redirect("/login"); } return ( -
    - {/* -------------------------------------------------- - Header - -------------------------------------------------- */} -
    -

    - Connect Xero -

    +
    + {/* Navigation */} + -

    - We need access to your Xero organisation so we can automatically - create invoices and mark them as paid when Stripe payments succeed. -

    -
    +
    +
    + {/* Header */} +
    +
    + + Step 3 of 3 +
    - {/* -------------------------------------------------- - What will happen - -------------------------------------------------- */} -
    -

    - What happens next -

    +

    + Connect Xero +

    -
      -
    • You’ll be redirected to Xero
    • -
    • You’ll choose which organisation to connect
    • -
    • You’ll be sent back here once connected
    • -
    -
    +

    + We need access to your Xero organisation to automatically create invoices and mark them as paid when Stripe payments succeed. +

    +
    - {/* -------------------------------------------------- - Trust / reassurance - -------------------------------------------------- */} -
    -

    - We never see your Xero password. -
    - Access can be revoked at any time from Xero. -

    -
    + {/* Two Column Layout */} +
    + {/* Left Column - Information */} +
    + {/* What we do */} +
    +

    What we can create

    +
      +
    • + + + +
      +

      Invoices

      +

      Sales invoices matched to Stripe payments

      +
      +
    • +
    • + + + +
      +

      Credit notes

      +

      For Stripe refunds and chargebacks

      +
      +
    • +
    • + + + +
      +

      Journal entries

      +

      For Stripe fees and reconciliation

      +
      +
    • +
    +
    - {/* -------------------------------------------------- - Primary action - -------------------------------------------------- */} -
    - - Connect Xero → - -
    -
    + {/* Important notes */} +
    +

    Important notes

    + +
    + + {/* How it works */} +
    +

    What happens next

    +
      +
    1. + 1 + You'll be securely redirected to Xero +
    2. +
    3. + 2 + Select which organisation to connect +
    4. +
    5. + 3 + Your dashboard will be ready to configure +
    6. +
    +
    + + + {/* Right Column - CTA Card */} +
    +
    +

    Almost there!

    + + Connect Xero → + +

    + You'll be redirected to Xero's secure OAuth page +

    +
    +
    + + + {/* Trust badges */} +
    +

    + 🔒 Your security matters: We use OAuth, so you can revoke access from Xero at any time. We never see or store your Xero password. +

    +
    + +
    + ); } diff --git a/stripe_to_invoice/app/connect/xero/success/page.tsx b/stripe_to_invoice/app/connect/xero/success/page.tsx index 4cdc8ce..11cb350 100644 --- a/stripe_to_invoice/app/connect/xero/success/page.tsx +++ b/stripe_to_invoice/app/connect/xero/success/page.tsx @@ -2,43 +2,125 @@ import Link from "next/link"; export default function XeroSuccessPage() { return ( -
    -

    - Xero connected 🎉 -

    +
    + {/* Navigation */} + -

    - Your Xero organisation is now linked. We can now automatically - create invoices and mark them as paid when Stripe payments succeed. -

    +
    +
    + {/* Success Animation */} +
    +
    + + + +
    - {/* Progress */} -
      -
    1. - - Logged in -
    2. +

      + All set! 🚀 +

      -
    3. - - Stripe connected -
    4. +

      + Your Xero organisation is now securely linked. We can now automatically create invoices and mark them as paid when Stripe payments succeed. +

      +
    -
  • - - Xero connected -
  • - + {/* Progress Card */} +
    +

    Setup complete

    - {/* Primary CTA */} -
    - - Go to dashboard → - -
    -
    +
    + {/* Step 1 - Login */} +
    +
    +
    + + + +
    +
    +
    +
    +

    Email verified

    +

    Authentication complete

    +
    +
    + + {/* Step 2 - Stripe */} +
    +
    +
    + + + +
    +
    +
    +
    +

    Stripe connected

    +

    Payment monitoring active

    +
    +
    + + {/* Step 3 - Xero */} +
    +
    +
    + + + +
    +
    +
    +

    Xero connected

    +

    Invoice automation enabled

    +
    +
    +
    +
    + + {/* What's next */} +
    +

    What happens now

    + +
    + + {/* CTA */} +
    +

    + Go to your dashboard +

    +

    + Configure your account codes and start using the automation. +

    + + Open dashboard → + +
    + +
    + ); } diff --git a/stripe_to_invoice/app/dashboard/page.tsx b/stripe_to_invoice/app/dashboard/page.tsx index 5315754..2e5ff2f 100644 --- a/stripe_to_invoice/app/dashboard/page.tsx +++ b/stripe_to_invoice/app/dashboard/page.tsx @@ -4,12 +4,12 @@ import { useEffect, useState } from "react"; export default function DashboardPage() { const [salesAccountCode, setSalesAccountCode] = useState(""); - const [stripeClearingAccountCode, setStripeClearingAccountCode] = - useState(""); + const [stripeClearingAccountCode, setStripeClearingAccountCode] = useState(""); const [stripeAccountId, setStripeAccountId] = useState(""); const [xeroTenantId, setXeroTenantId] = useState(""); const [loading, setLoading] = useState(true); const [saved, setSaved] = useState(false); + const [error, setError] = useState(null); useEffect(() => { Promise.all([ @@ -26,88 +26,195 @@ export default function DashboardPage() { async function save() { setSaved(false); + setError(null); - await fetch("/api/dashboard/xero-settings", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - salesAccountCode, - stripeClearingAccountCode, - }), - }); + try { + await fetch("/api/dashboard/xero-settings", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + salesAccountCode, + stripeClearingAccountCode, + }), + }); - setSaved(true); + setSaved(true); + setTimeout(() => setSaved(false), 3000); + } catch (err) { + setError("Failed to save settings. Please try again."); + } } - if (loading) return

    Loading…

    ; - - return ( -
    -

    - Stripe → Xero settings -

    - - {/* Connected Accounts */} -
    -

    Connected Accounts

    -
    -

    - Stripe:{" "} - - {stripeAccountId || "Not connected"} - -

    -

    - Xero:{" "} - - {xeroTenantId || "Not connected"} - -

    + if (loading) { + return ( +
    +
    +
    + +
    +

    Loading your settings…

    + ); + } -
    - - setSalesAccountCode(e.target.value)} - /> -

    - Used on invoice line items -

    -
    + return ( +
    + {/* Navigation */} + -
    - - - setStripeClearingAccountCode(e.target.value) - } - /> -

    - Receives Stripe payments -

    -
    +
    +
    + {/* Header */} +
    +

    Dashboard

    +

    + Configure your Xero account codes and manage your automation settings. +

    +
    - +
    + {/* Main Content */} +
    + {/* Connected Accounts */} +
    +

    Connected Accounts

    +
    +
    +

    Stripe Account

    +

    + {stripeAccountId || Not connected} +

    +
    +
    +

    Xero Organisation

    +

    + {xeroTenantId || Not connected} +

    +
    +
    +
    - {saved && ( -

    - Saved -

    - )} + {/* Account Configuration */} +
    +

    Xero Account Codes

    + +
    + {/* Sales Account Code */} +
    + + setSalesAccountCode(e.target.value)} + /> +

    + The Xero account code used for sales invoice line items. This is typically your revenue/sales account. +

    +
    + + {/* Stripe Clearing Account Code */} +
    + + setStripeClearingAccountCode(e.target.value)} + /> +

    + The Xero account code that receives Stripe payments. This is typically a bank or clearing account. +

    +
    +
    + + {/* Save Button and Feedback */} +
    + + + {saved && ( +
    + + + + Settings saved successfully +
    + )} + + {error && ( +
    + + + + {error} +
    + )} +
    +
    +
    + + {/* Sidebar */} +
    + {/* Info Card */} +
    +

    ℹ️ How it works

    +

    + When a Stripe payment is received, we automatically create an invoice in Xero using: +

    +
      +
    • + + Sales Account: Invoice line items +
    • +
    • + + Clearing Account: Payment received +
    • +
    +
    + + {/* Help Card */} +
    +

    🚀 Getting started

    +
      +
    1. 1. Set the account codes above
    2. +
    3. 2. Make a test payment in Stripe
    4. +
    5. 3. Check Xero for the invoice
    6. +
    7. 4. You're ready to go!
    8. +
    +
    + + {/* Status Card */} +
    +

    ✓ Status

    +

    Connected & Active

    +

    + Your automation is ready. New Stripe payments will create invoices in Xero automatically. +

    +
    +
    +
    +
    +
    ); } diff --git a/stripe_to_invoice/app/globals.css b/stripe_to_invoice/app/globals.css index e69de29..f1d8c73 100644 --- a/stripe_to_invoice/app/globals.css +++ b/stripe_to_invoice/app/globals.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/stripe_to_invoice/app/layout.tsx b/stripe_to_invoice/app/layout.tsx index f7fa87e..a52c49f 100644 --- a/stripe_to_invoice/app/layout.tsx +++ b/stripe_to_invoice/app/layout.tsx @@ -13,8 +13,15 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Stripe to Xero - Automated Invoice Creation", + description: "Automatically turn Stripe payments into paid Xero invoices with proper VAT handling and accounting compliance.", + keywords: ["Stripe", "Xero", "invoicing", "automation", "accounting", "VAT"], + authors: [{ name: "Stripe to Xero" }], + openGraph: { + title: "Stripe to Xero - Automated Invoice Creation", + description: "Automatically turn Stripe payments into paid Xero invoices with proper VAT handling.", + type: "website", + }, }; export default function RootLayout({ diff --git a/stripe_to_invoice/app/login/page.tsx b/stripe_to_invoice/app/login/page.tsx index e505048..02eb5f3 100644 --- a/stripe_to_invoice/app/login/page.tsx +++ b/stripe_to_invoice/app/login/page.tsx @@ -1,4 +1,3 @@ -// app/login/page.tsx "use client"; import { useState } from "react"; @@ -34,51 +33,125 @@ export default function LoginPage() { } } + const handleKeyPress = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !loading && email && step === "email") { + submit(); + } + }; + return ( -
    - +
    + {/* Navigation */} + - {step === "email" && ( - <> -

    Log in

    + {/* Main Content */} +
    +
    + {/* Progress Bar */} + - setEmail(e.target.value)} - disabled={loading} - /> + {/* Form Card */} +
    + {step === "email" && ( + <> +

    + Welcome back +

    +

    + Sign in to your Stripe to Xero automation dashboard +

    - +
    +
    + + setEmail(e.target.value)} + onKeyPress={handleKeyPress} + disabled={loading} + autoFocus + /> +
    - {error && ( -

    {error}

    - )} - - )} + - {step === "sent" && ( - <> -

    Check your email

    + {error && ( +
    +

    {error}

    +
    + )} +
    + + )} -

    - We sent a login link to {email}. + {step === "sent" && ( + <> +

    +
    + + + +
    + +

    + Check your email +

    + +

    + We've sent a login link to {email} +

    + +
    +

    + The link expires in 15 minutes. Check your spam folder if you don't see it. +

    +
    + + +
    + + )} +
    + + {/* Footer */} +

    + Magic link authentication is secure and passwordless

    - -

    - The link expires in 15 minutes. -

    - - )} -
    +
    +
    +
    ); } @@ -86,16 +159,15 @@ function Progress({ step }: { step: Step }) { const percent = step === "email" ? 50 : 100; return ( -
    -
    +
    +
    - -

    - {step === "email" ? "Enter email" : "Check inbox"} +

    + {step === "email" ? "Step 1 of 2 • Enter email" : "Step 2 of 2 • Check inbox"}

    ); diff --git a/stripe_to_invoice/app/page.tsx b/stripe_to_invoice/app/page.tsx index 99a477a..7b138e0 100644 --- a/stripe_to_invoice/app/page.tsx +++ b/stripe_to_invoice/app/page.tsx @@ -1,12 +1,3 @@ -// app/page.tsx -// -// CORE MVP PAGE -// Purpose: -// 1. Explain the automation -// 2. Point the user to the next action -// -// Everything else lives elsewhere. - import { cookies } from "next/headers"; import { redirect } from "next/navigation"; @@ -14,59 +5,284 @@ export default async function Home() { const cookieStore = await cookies(); const session = cookieStore.get("session"); - // ✅ If already logged in, go straight to app if (session) { redirect("/app"); } return ( -
    +
    + {/* Navigation */} + - {/* -------------------------------------------------- - What this is - -------------------------------------------------- */} -
    -

    - Stripe → Xero automation -

    +
    + {/* Hero Section */} +
    +
    + + Automate your invoicing +
    -

    - When a Stripe payment succeeds, a Xero invoice is - automatically created and marked as paid. -

    -
    +

    + Stripe payments, +
    + + Xero invoices + + {" "}automatically +

    - {/* -------------------------------------------------- - What the user does - -------------------------------------------------- */} -
    -

    - How it works -

    +

    + Stop manually creating invoices. When a Stripe payment succeeds, a Xero invoice is instantly created and marked as paid—with proper VAT handling and accountant-approved accuracy. +

    -
      -
    1. Log in with your email
    2. -
    3. Connect Stripe
    4. -
    5. Connect Xero
    6. -
    7. Invoices handle themselves. You focus on the business.
    8. -
    -
    + - {/* -------------------------------------------------- - Next action - -------------------------------------------------- */} -
    -

    - Start by logging in. -

    + {/* Trust badges */} +
    +
    + + + + No manual work +
    +
    + + + + VAT compliant +
    +
    + + + + Audit ready +
    +
    +
    - - Log in → - -
    -
    + {/* Features Section */} +
    +

    + How it works +

    +

    + Three simple connections, then automation takes over +

    + +
    + {/* Step 1 */} +
    +
    + 1 +
    +

    Connect Stripe

    +

    + Link your Stripe account to start monitoring payments in real-time. +

    +
    + + {/* Step 2 */} +
    +
    + 2 +
    +

    Connect Xero

    +

    + Authorize access to your Xero account for invoice creation. +

    +
    + + {/* Step 3 */} +
    +
    + 3 +
    +

    Done

    +

    + Relax as payments automatically become invoices in Xero. +

    +
    +
    + + {/* Benefits Grid */} +
    +
    +

    🎯 Zero manual work

    +

    + No more spreadsheets, journals, or month-end fixing. Invoices appear instantly and correctly. +

    +
    + +
    +

    ✓ Accounting ready

    +

    + VAT compliance built-in. Your accountant will love the audit trail. +

    +
    + +
    +

    ⚡ Instant & reliable

    +

    + Invoices created within seconds of payment. Refunds become credit notes automatically. +

    +
    + +
    +

    🔒 Xero is the source

    +

    + Your invoices remain immutable in Xero. Stripe is purely payment execution. +

    +
    +
    +
    + + {/* Perfect for section */} +
    +

    + Who this is for +

    + +
    +
    +

    ✓ Perfect fit:

    +
      +
    • + + UK businesses using Stripe & Xero +
    • +
    • + + VAT registered +
    • +
    • + + One-off, annual, or fixed recurring billing +
    • +
    • + + Invoices are currently manually created +
    • +
    +
    + +
    +

    ✗ Not a fit:

    +
      +
    • + + Usage-based or metered billing +
    • +
    • + + Proration or complex billing logic +
    • +
    • + + Already fully automated elsewhere +
    • +
    • + + Non-UK businesses +
    • +
    +
    +
    +
    + + {/* Pricing Section */} +
    +

    + Simple pricing +

    +

    + No hidden fees. No per-transaction costs. +

    + +
    +

    £200

    +

    per month

    +
      +
    • + + + + Unlimited invoices +
    • +
    • + + + + No per-transaction fees +
    • +
    • + + + + Full VAT handling +
    • +
    +

    + Usually saves £1000s per year in manual work and accounting fixes. +

    + + Start 14-day trial + +
    +
    + + {/* CTA Section */} +
    +
    +

    + Ready to automate? +

    +

    + Connect Stripe and Xero, then focus on what matters. Invoicing handles itself. +

    + + Get started free → + +
    +
    + + {/* Footer */} + + +
    ); } diff --git a/stripe_to_invoice/tailwind.config.ts b/stripe_to_invoice/tailwind.config.ts new file mode 100644 index 0000000..5a92783 --- /dev/null +++ b/stripe_to_invoice/tailwind.config.ts @@ -0,0 +1,12 @@ +import type { Config } from 'tailwindcss' + +const config: Config = { + content: [ + './app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: {}, + }, + plugins: [], +} +export default config