Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ai-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ jobs:
- name: Enforce severity threshold
run: |
out=/home/runner/work/_temp/claude-execution-output.json
if jq -r '.[] | select(.type=="result") | .result' "$out" 2>/dev/null | grep -q 'Verdict: \*\*PASS\*\*'; then
echo "AI review verdict: PASS"
else
echo "::error::AI review verdict is BLOCK or missing. Merge blocked."
if jq -r '.[] | select(.type=="result") | .result' "$out" 2>/dev/null | grep -q 'Verdict:.*BLOCK'; then
echo "::error::AI review verdict is BLOCK. Merge blocked."
exit 1
else
echo "AI review verdict: PASS (no explicit BLOCK found)"
fi
2 changes: 2 additions & 0 deletions asmita/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ EMAIL_FROM="Asmita <Notice@meriasmita.org>"
NOTICE_EMAIL_FROM="Asmita <Notice@meriasmita.org>"
TRANSACTIONAL_EMAIL_FROM="Asmita <Update@meriasmita.org>"
RESEND_FROM_EMAIL="Asmita <Notice@meriasmita.org>"
# Resend webhook signing secret (starts with whsec_). Get from Resend dashboard → Webhooks.
RESEND_WEBHOOK_SECRET=

# --- Queue + cache ----------------------------------------------------------
# Vercel serverless functions are stateless: REDIS_URL must point to a
Expand Down
43 changes: 43 additions & 0 deletions asmita/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions asmita/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@prisma/adapter-pg": "^7.8.0",
"@prisma/client": "^7.8.0",
"@types/qrcode": "^1.5.6",
"@vercel/analytics": "^2.0.1",
"bullmq": "^5.76.7",
"docx": "^9.7.1",
"dotenv": "^17.4.2",
Expand Down
60 changes: 36 additions & 24 deletions asmita/src/app/(auth)/register/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Step = "age" | "email" | "otp";
export function RegisterForm({ locale }: { locale: Locale }) {
const router = useRouter();
const [step, setStep] = useState<Step>("age");
const [ageConfirmed, setAgeConfirmed] = useState<"adult" | "minor" | null>(null);
const [ageConfirmed, setAgeConfirmed] = useState<"adult" | "minor" | "">("");
const [email, setEmail] = useState("");
const [otp, setOtp] = useState("");
const [error, setError] = useState("");
Expand All @@ -25,9 +25,9 @@ export function RegisterForm({ locale }: { locale: Locale }) {
function continueFromAge() {
if (ageConfirmed === "minor") {
router.push("/minor-support");
} else {
setStep("email");
return;
}
setStep("email");
}

async function requestOtp() {
Expand Down Expand Up @@ -85,37 +85,49 @@ export function RegisterForm({ locale }: { locale: Locale }) {
<p className="muted mt-2 text-sm leading-[1.75]">
{t(locale, "reg.age.sub")}
</p>
<div className="mt-8 space-y-3">
<button
type="button"
onClick={() => setAgeConfirmed("adult")}
className={`w-full rounded-xl border p-4 text-left transition-colors ${
<div className="mt-6 space-y-3">
<label
className={`flex cursor-pointer items-start gap-3 rounded-xl border p-4 transition-colors ${
ageConfirmed === "adult"
? "border-[var(--teal)] bg-[var(--teal)]/5 text-[var(--foreground)]"
: "border-[var(--border)] bg-[var(--surface)] text-[var(--foreground)]"
? "border-[var(--teal)] bg-[var(--teal-soft)]"
: "border-[var(--hairline)] bg-[var(--background)] hover:border-[var(--border)]"
}`}
>
I am 18 years of age or older.
</button>
<button
type="button"
onClick={() => setAgeConfirmed("minor")}
className={`w-full rounded-xl border p-4 text-left transition-colors ${
<input
type="radio"
checked={ageConfirmed === "adult"}
onChange={() => setAgeConfirmed("adult")}
className="mt-[3px] h-4 w-4 shrink-0 accent-[var(--teal)]"
/>
<span className="text-[15px] font-semibold leading-[1.4] text-[var(--foreground)]">
{t(locale, "auth.ageAdult")}
</span>
</label>
<label
className={`flex cursor-pointer items-start gap-3 rounded-xl border p-4 transition-colors ${
ageConfirmed === "minor"
? "border-[var(--teal)] bg-[var(--teal)]/5 text-[var(--foreground)]"
: "border-[var(--border)] bg-[var(--surface)] text-[var(--foreground)]"
? "border-[var(--teal)] bg-[var(--teal-soft)]"
: "border-[var(--hairline)] bg-[var(--background)] hover:border-[var(--border)]"
}`}
>
I am under 18 years of age.
</button>
<input
type="radio"
checked={ageConfirmed === "minor"}
onChange={() => setAgeConfirmed("minor")}
className="mt-[3px] h-4 w-4 shrink-0 accent-[var(--teal)]"
/>
<span className="text-[15px] font-semibold leading-[1.4] text-[var(--foreground)]">
{t(locale, "auth.ageMinor")}
</span>
</label>
</div>
<button
className="btn btn-primary mt-6"
disabled={!ageConfirmed}
type="button"
className="btn btn-primary mt-8"
disabled={!ageConfirmed || !hydrated}
onClick={continueFromAge}
type="button"
>
Continue
{t(locale, "reg.otp.verifyBtn")}
</button>
</div>
)}
Expand Down
2 changes: 2 additions & 0 deletions asmita/src/app/(public)/faq/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default async function FaqPage() {
{ question: t(locale, "faq.s1.q2"), answer: t(locale, "faq.s1.a2") },
{ question: t(locale, "faq.s1.q3"), answer: t(locale, "faq.s1.a3") },
{ question: t(locale, "faq.s1.q4"), answer: t(locale, "faq.s1.a4") },
{ question: t(locale, "faq.s1.q5"), answer: t(locale, "faq.s1.a5") },
],
},
{
Expand Down Expand Up @@ -50,6 +51,7 @@ export default async function FaqPage() {
{ question: t(locale, "faq.s4.q3"), answer: t(locale, "faq.s4.a3") },
{ question: t(locale, "faq.s4.q4"), answer: t(locale, "faq.s4.a4") },
{ question: t(locale, "faq.s4.q5"), answer: t(locale, "faq.s4.a5") },
{ question: t(locale, "faq.s4.q6"), answer: t(locale, "faq.s4.a6") },
],
},
];
Expand Down
8 changes: 5 additions & 3 deletions asmita/src/app/(public)/how-it-works/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ export default async function HowItWorksPage() {
{ num: "02", title: t(locale, "hiw.step2.title"), body: t(locale, "hiw.step2.body") },
{ num: "03", title: t(locale, "hiw.step3.title"), body: t(locale, "hiw.step3.body") },
{ num: "04", title: t(locale, "hiw.step4.title"), body: t(locale, "hiw.step4.body") },
{ num: "05", title: t(locale, "hiw.step5.title"), body: t(locale, "hiw.step5.body") },
{ num: "06", title: t(locale, "hiw.step6.title"), body: t(locale, "hiw.step6.body") },
];

const tiers = [
{ label: "Tier 01", icon: "", title: t(locale, "hiw.tier1.title"), body: t(locale, "hiw.tier1.body") },
{ label: "Tier 02", icon: "", title: t(locale, "hiw.tier2.title"), body: t(locale, "hiw.tier2.body") },
{ label: "Tier 03", icon: "", title: t(locale, "hiw.tier3.title"), body: t(locale, "hiw.tier3.body") },
{ label: "Tier 01", icon: "", title: t(locale, "hiw.tier1.title"), body: t(locale, "hiw.tier1.body") },
{ label: "Tier 02", icon: "", title: t(locale, "hiw.tier2.title"), body: t(locale, "hiw.tier2.body") },
{ label: "Tier 03", icon: "", title: t(locale, "hiw.tier3.title"), body: t(locale, "hiw.tier3.body") },
];

const timeline = [
Expand Down
14 changes: 4 additions & 10 deletions asmita/src/app/(public)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function HomePage() {
<AppShell>
<div className="page-canvas">
{/* HERO - centered */}
<section className="container pb-20 pt-20 text-center md:pb-28 md:pt-32">
<section className="container pb-20 pt-10 text-center md:pb-28 md:pt-16">
<div className="mx-auto max-w-2xl">
<span className="pill">
<span className="dot" />
Expand Down Expand Up @@ -51,20 +51,17 @@ export default async function HomePage() {
</span>
</Link>
</p>
<p className="muted mx-auto mt-12 max-w-md text-[13px] leading-[1.7]">
{t(locale, "home.hero.noFetch")}
</p>
</div>
</section>

<div className="container">
<div className="hairline" />
</div>

{/* VALIDATION - trauma-informed affirmation */}
{/* VALIDATION - privacy assurance */}
<section className="container py-12 text-center md:py-16">
<p className="font-display mx-auto max-w-2xl text-xl leading-[1.55] tracking-tight text-[var(--foreground)] md:text-2xl md:leading-[1.5]">
{t(locale, "home.validation")}
<p className="muted mx-auto max-w-lg text-base leading-[1.7] md:text-lg md:leading-[1.7]">
{t(locale, "home.hero.noFetch")}
</p>
</section>

Expand Down Expand Up @@ -191,9 +188,6 @@ export default async function HomePage() {
{t(locale, "home.closing.cta2")}
</Link>
</div>
<p className="muted mx-auto mt-14 max-w-md text-[13px] leading-[1.7]">
{t(locale, "home.closing.partners")}
</p>
</div>
</section>
</div>
Expand Down
2 changes: 1 addition & 1 deletion asmita/src/app/(public)/privacy/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export default async function PrivacyPage() {
<PolicySection num="05" id="why-we-collect" title={t(locale, "privacy.toc.05")}>
<p>{t(locale, "privacy.s05.intro")}</p>
<ul className="mt-4 space-y-3">
{(["i1","i2","i3","i4"] as const).map((i) => (
{(["i1","i2","i2b","i3","i4"] as const).map((i) => (
<li key={i}>
<span className="font-semibold text-[var(--foreground)]">{t(locale, `privacy.s05.${i}.bold` as Parameters<typeof t>[1])}</span>{" "}
{t(locale, `privacy.s05.${i}.detail` as Parameters<typeof t>[1])}
Expand Down
Loading
Loading