Prettier format pending files

This commit is contained in:
Builder.io 2025-10-19 06:00:42 +00:00
parent 47b9b4a0bd
commit 2d25128ee1
12 changed files with 190 additions and 42 deletions

View file

@ -1,6 +1,12 @@
import { useEffect, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
@ -36,11 +42,15 @@ export default function LeadForm() {
}));
}, [inferred.full, inferred.email]);
const update = (k: keyof typeof form) => (e: any) => setForm({ ...form, [k]: e.target.value });
const update = (k: keyof typeof form) => (e: any) =>
setForm({ ...form, [k]: e.target.value });
const submit = async () => {
if (!form.email) {
toast({ title: "Email required", description: "Please provide a valid email." });
toast({
title: "Email required",
description: "Please provide a valid email.",
});
return;
}
setLoading(true);
@ -53,10 +63,17 @@ export default function LeadForm() {
const ok = r.ok;
const data = await r.json().catch(() => ({}));
if (!ok) throw new Error(data?.error || `Request failed (${r.status})`);
toast({ title: "Thanks!", description: "Well follow up shortly with next steps." });
toast({
title: "Thanks!",
description: "Well follow up shortly with next steps.",
});
setForm({ ...form, message: "" });
} catch (e: any) {
toast({ title: "Submission failed", description: e?.message || "Try again later.", variant: "destructive" as any });
toast({
title: "Submission failed",
description: e?.message || "Try again later.",
variant: "destructive" as any,
});
} finally {
setLoading(false);
}
@ -67,39 +84,81 @@ export default function LeadForm() {
<Card className="border-border/40 bg-card/60 backdrop-blur">
<CardHeader>
<CardTitle>Start a Wix project</CardTitle>
<CardDescription>Tell us a bit about your goals. Well get back within 1 business day.</CardDescription>
<CardDescription>
Tell us a bit about your goals. Well get back within 1 business
day.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="name">Name</Label>
<Input id="name" value={form.name} onChange={update("name")} placeholder="Your name" />
<Input
id="name"
value={form.name}
onChange={update("name")}
placeholder="Your name"
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" value={form.email} onChange={update("email")} placeholder="you@company.com" />
<Input
id="email"
value={form.email}
onChange={update("email")}
placeholder="you@company.com"
/>
</div>
<div className="space-y-2">
<Label htmlFor="company">Company</Label>
<Input id="company" value={form.company} onChange={update("company")} placeholder="Company Inc." />
<Input
id="company"
value={form.company}
onChange={update("company")}
placeholder="Company Inc."
/>
</div>
<div className="space-y-2">
<Label htmlFor="website">Website</Label>
<Input id="website" value={form.website} onChange={update("website")} placeholder="https://example.com" />
<Input
id="website"
value={form.website}
onChange={update("website")}
placeholder="https://example.com"
/>
</div>
<div className="space-y-2">
<Label htmlFor="budget">Budget</Label>
<Input id="budget" value={form.budget} onChange={update("budget")} placeholder="e.g. $5k$10k" />
<Input
id="budget"
value={form.budget}
onChange={update("budget")}
placeholder="e.g. $5k$10k"
/>
</div>
<div className="space-y-2">
<Label htmlFor="timeline">Timeline</Label>
<Input id="timeline" value={form.timeline} onChange={update("timeline")} placeholder="e.g. 46 weeks" />
<Input
id="timeline"
value={form.timeline}
onChange={update("timeline")}
placeholder="e.g. 46 weeks"
/>
</div>
<div className="space-y-2 md:col-span-2">
<Label htmlFor="message">Project overview</Label>
<Textarea id="message" value={form.message} onChange={update("message")} placeholder="What are you building? Who is it for? What does success look like?" />
<Textarea
id="message"
value={form.message}
onChange={update("message")}
placeholder="What are you building? Who is it for? What does success look like?"
/>
</div>
<div className="md:col-span-2">
<Button onClick={submit} disabled={loading} className="w-full md:w-auto">
<Button
onClick={submit}
disabled={loading}
className="w-full md:w-auto"
>
{loading ? "Submitting…" : "Submit"}
</Button>
</div>

View file

@ -1,4 +1,10 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import type { PricingTier } from "@/data/wix/pricing";

View file

@ -1,4 +1,10 @@
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
export default function ServiceCard({
name,

View file

@ -10,7 +10,10 @@ export default function WixHero() {
<CardContent className="p-6 md:p-10">
<div className="flex flex-col gap-4 md:gap-6">
<div className="flex items-center gap-2">
<Badge variant="outline" className="border-aethex-400/50 text-aethex-300">
<Badge
variant="outline"
className="border-aethex-400/50 text-aethex-300"
>
Official Wix Agency Partner
</Badge>
</div>
@ -18,8 +21,9 @@ export default function WixHero() {
Wix & Wix Studio Sites designed, built, and scaled by AeThex
</h1>
<p className="text-muted-foreground text-base md:text-lg max-w-3xl">
We ship fast, accessible, and SEO-ready sites using Wix Studio. From launch
microsites to full eCommerce, your team gets a site you can actually edit.
We ship fast, accessible, and SEO-ready sites using Wix Studio.
From launch microsites to full eCommerce, your team gets a site
you can actually edit.
</p>
<div className="flex flex-wrap gap-3">
<Button asChild>
@ -32,7 +36,13 @@ export default function WixHero() {
<Link to="/wix/faq">FAQ</Link>
</Button>
<Button asChild variant="outline">
<a href="https://www.wix.com/studio/community/partners/aethex" target="_blank" rel="noreferrer">Wix Partner Profile</a>
<a
href="https://www.wix.com/studio/community/partners/aethex"
target="_blank"
rel="noreferrer"
>
Wix Partner Profile
</a>
</Button>
</div>
</div>

View file

@ -271,11 +271,17 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
// Auto-seed owner roles if logging in as site owner
const normalizedEmail = userProfile?.email?.toLowerCase();
if (normalizedEmail === "mrpiglr@gmail.com" && !r.includes("owner")) {
const seeded = Array.from(new Set(["owner", "admin", "founder", ...r]));
const seeded = Array.from(
new Set(["owner", "admin", "founder", ...r]),
);
await aethexRoleService.setUserRoles(userId, seeded);
r = seeded;
}
if (normalizedEmail && /@aethex\.dev$/i.test(normalizedEmail) && !r.includes("staff")) {
if (
normalizedEmail &&
/@aethex\.dev$/i.test(normalizedEmail) &&
!r.includes("staff")
) {
const seeded = Array.from(new Set(["staff", ...r]));
await aethexRoleService.setUserRoles(userId, seeded);
r = seeded;

View file

@ -1,7 +1,15 @@
export type Partner = { name: string; tier?: string | null; url?: string | null };
export type Partner = {
name: string;
tier?: string | null;
url?: string | null;
};
export const partners: Partner[] = [
{ name: "Wix", tier: "Official Agency Partner", url: "https://www.wix.com/studio/community/partners/aethex" },
{
name: "Wix",
tier: "Official Agency Partner",
url: "https://www.wix.com/studio/community/partners/aethex",
},
];
export default partners;

View file

@ -12,7 +12,8 @@ export const pricing: PricingTier[] = [
id: "starter",
name: "Starter",
price: "From $2,500",
description: "Single-page or small brochure site with strong SEO and fast turnaround.",
description:
"Single-page or small brochure site with strong SEO and fast turnaround.",
features: [
"13 pages",
"Wix Studio setup and theme",

View file

@ -49,16 +49,21 @@ function OrgLogin() {
<div className="space-y-3 p-3 rounded border border-border/40 bg-background/50">
<div className="flex items-center justify-between">
<div className="text-sm font-medium">Aethex Login (org)</div>
<Badge variant="outline" className="uppercase">@aethex.dev</Badge>
<Badge variant="outline" className="uppercase">
@aethex.dev
</Badge>
</div>
{sent ? (
<Alert className="border-aethex-400/30 bg-aethex-500/10 text-foreground">
<AlertTitle>Check your inbox</AlertTitle>
<AlertDescription>
We sent a magic link to {email}. If email isnt configured, a manual link is shown below.
We sent a magic link to {email}. If email isnt configured, a manual
link is shown below.
</AlertDescription>
{sent.startsWith("http") && (
<p className="mt-2 break-all rounded bg-background/60 px-3 py-2 font-mono text-xs text-foreground/90">{sent}</p>
<p className="mt-2 break-all rounded bg-background/60 px-3 py-2 font-mono text-xs text-foreground/90">
{sent}
</p>
)}
</Alert>
) : null}
@ -88,7 +93,10 @@ function OrgLogin() {
const r = await fetch("/api/auth/send-org-link", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email, redirectTo: window.location.origin + "/dashboard" }),
body: JSON.stringify({
email,
redirectTo: window.location.origin + "/dashboard",
}),
});
if (!r.ok) {
const msg = await r.text().catch(() => "");

View file

@ -29,7 +29,9 @@ export default function ProjectsAdmin() {
const isOwner = Boolean(
user?.email?.toLowerCase() === "mrpiglr@gmail.com" ||
(roles || []).some((r) =>
["owner", "admin", "founder", "staff"].includes(String(r).toLowerCase()),
["owner", "admin", "founder", "staff"].includes(
String(r).toLowerCase(),
),
),
);
const [list, setList] = useState<any[]>([]);

View file

@ -13,10 +13,17 @@ export default function Wix() {
<WixHero />
<section className="container mx-auto px-4 py-10">
<h2 className="text-2xl md:text-3xl font-semibold mb-6">What we build</h2>
<h2 className="text-2xl md:text-3xl font-semibold mb-6">
What we build
</h2>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{services.map((s) => (
<ServiceCard key={s.id} name={s.name} summary={s.summary} highlights={s.highlights} />
<ServiceCard
key={s.id}
name={s.name}
summary={s.summary}
highlights={s.highlights}
/>
))}
</div>
</section>

View file

@ -1,5 +1,11 @@
import Layout from "@/components/Layout";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import studies from "@/data/wix/caseStudies";
export default function WixCaseStudies() {
@ -7,10 +13,15 @@ export default function WixCaseStudies() {
<Layout>
<div className="min-h-screen bg-aethex-gradient py-10">
<section className="container mx-auto px-4">
<h1 className="text-3xl md:text-4xl font-bold mb-6">Wix Case Studies</h1>
<h1 className="text-3xl md:text-4xl font-bold mb-6">
Wix Case Studies
</h1>
<div className="grid gap-6 md:grid-cols-2">
{studies.map((c) => (
<Card key={c.id} className="border-border/40 bg-card/60 backdrop-blur">
<Card
key={c.id}
className="border-border/40 bg-card/60 backdrop-blur"
>
<CardHeader>
<CardTitle>{c.title}</CardTitle>
<CardDescription>{c.summary}</CardDescription>
@ -18,7 +29,10 @@ export default function WixCaseStudies() {
<CardContent>
<div className="grid grid-cols-3 gap-3 text-sm">
{c.metrics.map((m, i) => (
<div key={i} className="rounded border border-border/40 p-3">
<div
key={i}
className="rounded border border-border/40 p-3"
>
<div className="text-muted-foreground">{m.label}</div>
<div className="font-semibold">{m.value}</div>
</div>

View file

@ -147,11 +147,17 @@ export function createServer() {
// Org domain magic-link sender (Aethex)
app.post("/api/auth/send-org-link", async (req, res) => {
try {
const { email, redirectTo } = (req.body || {}) as { email?: string; redirectTo?: string };
const target = String(email || "").trim().toLowerCase();
const { email, redirectTo } = (req.body || {}) as {
email?: string;
redirectTo?: string;
};
const target = String(email || "")
.trim()
.toLowerCase();
if (!target) return res.status(400).json({ error: "email is required" });
const allowed = /@aethex\.dev$/i.test(target);
if (!allowed) return res.status(403).json({ error: "domain not allowed" });
if (!allowed)
return res.status(403).json({ error: "domain not allowed" });
if (!adminSupabase?.auth?.admin) {
return res.status(500).json({ error: "Supabase admin unavailable" });
@ -163,7 +169,10 @@ export function createServer() {
process.env.SITE_URL ??
"https://aethex.dev";
const toUrl = typeof redirectTo === "string" && redirectTo.startsWith("http") ? redirectTo : fallbackRedirect;
const toUrl =
typeof redirectTo === "string" && redirectTo.startsWith("http")
? redirectTo
: fallbackRedirect;
const { data, error } = await adminSupabase.auth.admin.generateLink({
type: "magiclink" as any,
@ -1310,7 +1319,16 @@ export function createServer() {
// Leads: capture website leads (Wix microsite and others)
app.post("/api/leads", async (req, res) => {
const { name, email, company, website, budget, timeline, message, source } = (req.body || {}) as {
const {
name,
email,
company,
website,
budget,
timeline,
message,
source,
} = (req.body || {}) as {
name?: string;
email?: string;
company?: string;
@ -1335,7 +1353,10 @@ export function createServer() {
try {
if (emailService.isConfigured) {
const base = process.env.PUBLIC_BASE_URL || process.env.SITE_URL || "https://aethex.dev";
const base =
process.env.PUBLIC_BASE_URL ||
process.env.SITE_URL ||
"https://aethex.dev";
await (emailService as any).sendInviteEmail({
to: process.env.VERIFY_SUPPORT_EMAIL || "support@aethex.biz",
inviteUrl: `${base}/wix`,