Feedback Widget
A centralized feedback system built into the @anglinai/ui CorporateFooter component. Users on any AnglinAI project can submit feedback, which is stored in the tagzen Supabase database and emailed to larry@anglin.com.
How It Works
- User clicks Send Feedback in the footer
- A compact form appears with a comment field and optional email
- On submit, the widget POSTs to the centralized Supabase Edge Function
- The function inserts into the
feedbacktable and sends an email notification via Resend
Adding to a Project
Pass the feedbackEndpoint prop to CorporateFooter:
import { CorporateFooter } from '@anglinai/ui';
<CorporateFooter feedbackEndpoint="https://dktmitcptketnziahoho.supabase.co/functions/v1/feedback" feedbackProjectName="my-project-name" versionProps={...}/>| Prop | Type | Required | Description |
|---|---|---|---|
feedbackEndpoint | string | No | URL of the feedback Edge Function. Widget only renders when this is set. |
feedbackProjectName | string | No | Identifies which project the feedback came from. Falls back to the page hostname. |
If feedbackEndpoint is omitted, the footer behaves exactly as before β no widget is rendered.
Using the FeedbackWidget Standalone
The widget is also exported on its own if you want to place it somewhere other than the footer:
import { FeedbackWidget } from '@anglinai/ui';
<FeedbackWidget feedbackEndpoint="https://dktmitcptketnziahoho.supabase.co/functions/v1/feedback" projectName="my-project"/>Edge Function
URL: https://dktmitcptketnziahoho.supabase.co/functions/v1/feedback
Method: POST
Request body:
{ "pageUrl": "https://example.com/dashboard", "comment": "The export button doesn't work on mobile", "email": "user@example.com", "project": "my-project", "userAgent": "Mozilla/5.0 ..."}| Field | Type | Required | Description |
|---|---|---|---|
pageUrl | string | Yes | Full URL of the page the user was on (auto-captured) |
comment | string | Yes | Userβs feedback (max 5000 chars) |
email | string | No | Userβs email for follow-up |
project | string | No | Project identifier (auto-extracted from URL hostname if omitted) |
userAgent | string | No | Browser user agent (auto-captured) |
Success response (201):
{ "success": true, "data": { "message": "Feedback submitted successfully" }, "meta": { "timestamp": "2026-02-21T12:00:00.000Z" }}Database
Table: public.feedback (tagzen Supabase instance)
| Column | Type | Notes |
|---|---|---|
id | uuid | Primary key, auto-generated |
page_url | text | NOT NULL |
comment | text | NOT NULL |
email | text | Nullable |
project | text | Extracted from URL or passed by client |
user_agent | text | Nullable |
created_at | timestamptz | Auto-set |
RLS: Anyone can insert. Only service role can read (admin-only access).
Index: idx_feedback_project_created on (project, created_at DESC).
Querying Feedback
Use the Supabase dashboard or the service role key:
-- All feedback, newest firstSELECT * FROM feedback ORDER BY created_at DESC;
-- Feedback for a specific projectSELECT * FROM feedback WHERE project = 'accessible-org-chart' ORDER BY created_at DESC;
-- Feedback with email (users who want a reply)SELECT * FROM feedback WHERE email IS NOT NULL ORDER BY created_at DESC;Email Notifications
Every submission triggers an email to larry@anglin.com via Resend with:
- Subject line showing the project name and a preview of the comment
- The full comment, page URL, and email (if provided)
- AnglinAI branded template (royal blue header, white body)
The email send is non-blocking β if Resend is down, the feedback is still saved to the database.
Files
| File | Location | Purpose |
|---|---|---|
feedback-widget.tsx | anglinai-monorepo/packages/ui/src/components/ | React component |
corporate-footer.tsx | anglinai-monorepo/packages/ui/src/components/ | Footer integration |
feedback/index.ts | tagzen/supabase/functions/ | Supabase Edge Function |
20260221000001_feedback_table.sql | tagzen/supabase/migrations/ | Database migration |