{"id":49092716,"url":"https://github.com/rafactx/nextjs-testimonial-form","last_synced_at":"2026-04-20T19:10:46.305Z","repository":{"id":330733790,"uuid":"1123761268","full_name":"rafactx/nextjs-testimonial-form","owner":"rafactx","description":"Production-ready testimonial form with chat UI, Google Sheets integration, and modern stack (Next.js 16, React 19, TypeScript, Biome)","archived":false,"fork":false,"pushed_at":"2025-12-27T16:23:01.000Z","size":444,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-29T12:13:39.510Z","etag":null,"topics":["biome","chat-interface","form","google-sheets","nextjs","react","shadcn-ui","tailwindcss","testimonials","typescript"],"latest_commit_sha":null,"homepage":"https://depoimentodavince.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rafactx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-27T15:07:59.000Z","updated_at":"2025-12-27T16:23:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rafactx/nextjs-testimonial-form","commit_stats":null,"previous_names":["rafactx/nextjs-testimonial-form"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rafactx/nextjs-testimonial-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafactx%2Fnextjs-testimonial-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafactx%2Fnextjs-testimonial-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafactx%2Fnextjs-testimonial-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafactx%2Fnextjs-testimonial-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rafactx","download_url":"https://codeload.github.com/rafactx/nextjs-testimonial-form/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafactx%2Fnextjs-testimonial-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32061427,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["biome","chat-interface","form","google-sheets","nextjs","react","shadcn-ui","tailwindcss","testimonials","typescript"],"created_at":"2026-04-20T19:10:45.665Z","updated_at":"2026-04-20T19:10:46.300Z","avatar_url":"https://github.com/rafactx.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./public/images/davince-logo.jpeg\" alt=\"Davince Band Logo\" width=\"200\"/\u003e\n\n  # Next.js Testimonial Form\n\n  **Production-ready testimonial collection with Google Sheets integration**\n\n  [![CI](https://github.com/rafactx/nextjs-testimonial-form/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/rafactx/nextjs-testimonial-form/actions/workflows/ci.yml)\n  [![Next.js](https://img.shields.io/badge/Next.js-16-black?style=flat-square\u0026logo=next.js)](https://nextjs.org/)\n  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?style=flat-square\u0026logo=typescript)](https://www.typescriptlang.org/)\n  [![Biome](https://img.shields.io/badge/Biome-2.3-60a5fa?style=flat-square\u0026logo=biome)](https://biomejs.dev/)\n  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](./LICENSE)\n\n  [Features](#features) • [Quick Start](#quick-start) • [CI/CD](#cicd-setup) • [Deployment](#deployment)\n\u003c/div\u003e\n\n---\n\n## About\n\nConversational testimonial form built with Next.js 16 App Router, featuring chat-style UI with typing animations. Data syncs automatically to Google Sheets.\n\nOriginally created for [Davince Band](https://davince.com.br), fully customizable for any testimonial collection use case.\n\n**Live Demo**: [Coming soon]\n\n### Key Highlights\n\n- 🚀 **Modern Stack** - Next.js 16, React 19, TypeScript, Tailwind CSS 4, Biome\n- 💬 **Chat Interface** - Conversational flow with realistic typing animations\n- ⚡ **Performance** - Memoized components, debounced scrolling, optimized re-renders\n- 📊 **Google Sheets** - Automatic data sync, no database required\n- 🔒 **Secure** - Environment validation, CSP headers, server-side credentials\n- 🎨 **Themeable** - Dark mode, customizable design tokens\n- 📱 **Responsive** - Mobile-first design, optimized for all screen sizes\n- ♿ **Accessible** - WCAG compliant, keyboard navigation\n\n## Features\n\n**User Experience**\n- Multi-step chat flow with typing animations\n- Character count (250 limit) with live feedback\n- Optional internal feedback field (not published)\n- Review screen with inline editing\n- Responsive layout optimized for mobile and desktop\n- Comprehensive loading \u0026 error states\n\n**Technical**\n- Server-side Google Sheets API integration\n- Build-time environment validation\n- Type-safe error handling with custom error classes\n- Optimized image formats (AVIF/WebP)\n- Security headers (CSP, X-Frame-Options, HSTS)\n- Pre-commit hooks with Husky + lint-staged\n\n## Quick Start\n\n**Prerequisites**: [Bun](https://bun.sh/) ≥1.0 or Node.js ≥24\n\n```bash\n# Clone \u0026 install\ngit clone https://github.com/rafactx/nextjs-testimonial-form.git\ncd nextjs-testimonial-form\nbun install\n\n# Configure environment\ncp .env.local.example .env.local\n# Edit .env.local with your Google Sheets credentials\n\n# Start dev server\nbun dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000)\n\n### Google Sheets Setup\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eComplete configuration guide\u003c/b\u003e\u003c/summary\u003e\n\n#### 1. Create Service Account\n\n1. Go to [Google Cloud Console](https://console.cloud.google.com/)\n2. Create project → **APIs \u0026 Services** → **Credentials**\n3. **Create Credentials** → **Service Account**\n4. Complete form → **Create** → Skip permissions → **Done**\n\n#### 2. Generate JSON Key\n\n1. Select service account → **Keys** tab\n2. **Add Key** → **Create new key** → **JSON**\n3. Download and store securely (never commit to git)\n\n#### 3. Enable API\n\n1. **APIs \u0026 Services** → **Library**\n2. Search \"Google Sheets API\" → **Enable**\n\n#### 4. Configure Spreadsheet\n\n1. Create new Google Sheet\n2. Share with service account email (from JSON) as **Editor**\n3. Copy spreadsheet ID from URL: `docs.google.com/spreadsheets/d/{ID}/edit`\n\n#### 5. Environment Variables\n\nMap JSON values to `.env.local`:\n\n```env\nGOOGLE_SHEETS_CLIENT_EMAIL=your-account@project.iam.gserviceaccount.com\nGOOGLE_SHEETS_PRIVATE_KEY=\"-----BEGIN PRIVATE KEY-----\\nYour_Key\\n-----END PRIVATE KEY-----\\n\"\nGOOGLE_SHEETS_SPREADSHEET_ID=your-spreadsheet-id\nGOOGLE_SHEETS_SHEET_NAME=Sheet1\n```\n\n⚠️ **Important**: Keep `\\n` in `PRIVATE_KEY` (they're line breaks, not literal text)\n\n\u003c/details\u003e\n\n## CI/CD Setup\n\n### GitHub Actions\n\nThe repository includes a CI workflow ([.github/workflows/ci.yml](.github/workflows/ci.yml)) that runs on push/PR:\n\n1. **Lint \u0026 Check** - Biome linting, formatting, and type checking\n2. **Build** - Next.js production build with mock env vars\n\n**No secrets needed for CI** - build uses mock values to validate env var existence.\n\n### Configuring Secrets (for deployment)\n\nFor production deployments on Vercel/other platforms:\n\n1. **GitHub Environments** (recommended for security):\n   - Settings → Environments → **New environment** (e.g., \"Production\")\n   - Add secrets:\n     - `GOOGLE_SHEETS_CLIENT_EMAIL`\n     - `GOOGLE_SHEETS_PRIVATE_KEY`\n     - `GOOGLE_SHEETS_SPREADSHEET_ID`\n     - `GOOGLE_SHEETS_SHEET_NAME`\n   - Configure **Required reviewers** for approval gate\n   - Enable **Branch protection** on `main`\n\n2. **Vercel Integration**:\n   - Link GitHub repo to Vercel project\n   - Add environment variables in Vercel dashboard\n   - Auto-deploy on push to `main`\n\n## Scripts\n\n```bash\n# Development\nbun dev              # Start dev server with hot reload\nbun build            # Production build\nbun start            # Production server\n\n# Code Quality\nbun lint             # Run Biome linter\nbun lint:fix         # Auto-fix Biome issues\nbun format           # Format code with Biome\nbun format:check     # Verify formatting\nbun check            # Lint + format + fix (pre-commit)\nbun ci               # CI mode (strict, no fixes)\n```\n\n## Deployment\n\n### Vercel (Recommended)\n\n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/rafactx/nextjs-testimonial-form)\n\n**Steps**:\n1. Import repository on [vercel.com](https://vercel.com)\n2. Add environment variables (see [Google Sheets Setup](#google-sheets-setup))\n3. Deploy\n\n**CLI**:\n```bash\nbun add -g vercel\nvercel login\nvercel --prod\n```\n\n### Other Platforms\n\nWorks with any Next.js-supporting platform:\n- **Netlify** - Use Next.js Runtime plugin\n- **Railway** - Auto-deploy from Git\n- **Render** - Connect repository\n- **AWS Amplify** - Git-based deployment\n\n## Architecture\n\n```\ntestimonial-form/\n├── app/                    # Next.js App Router\n│   ├── api/testimonials/  # Submission endpoint (POST)\n│   ├── layout.tsx         # Root layout + ThemeProvider\n│   └── page.tsx           # Main page\n├── components/\n│   ├── ui/               # Base components (shadcn/ui)\n│   └── testimonial-form.tsx # Main form (585 lines)\n├── lib/\n│   ├── env.ts            # Build-time validation\n│   ├── errors.ts         # Type-safe error classes\n│   ├── google-sheets.ts  # Sheets API client\n│   └── utils.ts          # Utilities (cn helper)\n└── .github/workflows/    # CI pipeline\n```\n\n## Troubleshooting\n\n### Build Errors\n\n**`Variáveis de ambiente faltando`**\n- **Cause**: Missing required env vars\n- **Fix**: Verify `.env.local` has all 4 variables from [Google Sheets Setup](#google-sheets-setup)\n- **CI**: Use mock values (already configured in [ci.yml](.github/workflows/ci.yml))\n\n**`Error: Could not load the default credentials`**\n- **Cause**: Invalid service account credentials\n- **Fix**: Re-download JSON key, verify `PRIVATE_KEY` includes `\\n` characters\n\n### Runtime Errors\n\n**`API Request failed with status 403`**\n- **Cause**: Service account lacks spreadsheet access\n- **Fix**: Share spreadsheet with service account email as Editor\n\n**`Error: Unable to parse range`**\n- **Cause**: `SHEET_NAME` doesn't match actual sheet name\n- **Fix**: Check sheet tab name in Google Sheets (default: \"Sheet1\")\n\n### Development Issues\n\n**Pre-commit hook not running**\n- **Fix**: `chmod +x .husky/pre-commit \u0026\u0026 git add .husky/pre-commit`\n\n**Biome errors on CSS files**\n- **Expected**: Biome skips CSS (Tailwind not supported), only lints TS/JS/JSON\n\n**Port 3000 already in use**\n- **Fix**: `lsof -ti:3000 | xargs kill -9` or change port: `bun dev -- -p 3001`\n\n## Customization\n\n### Theme\n\nModify design tokens in [app/globals.css](app/globals.css):\n\n```css\n@theme inline {\n  --color-primary: #3b82f6;\n  --color-secondary: #8b5cf6;\n  /* Add custom colors */\n}\n```\n\n### Messages\n\nEdit conversation flow in [components/testimonial-form.tsx](components/testimonial-form.tsx):\n\n```tsx\nconst botMessages: Record\u003cStep, string[]\u003e = useMemo(() =\u003e ({\n  name: [\"Custom greeting!\", \"What's your name?\"],\n  testimonial: [\"Tell us about your experience...\"],\n  // ...\n}), [])\n```\n\n### Data Schema\n\nTestimonials saved to Google Sheets:\n\n| Timestamp | Name | Testimonial | Internal Feedback |\n|-----------|------|-------------|-------------------|\n| 2025-12-27 10:30 | John Doe | Amazing! | Feature request X |\n\n## Performance\n\n**Optimizations**:\n- Component memoization (`React.memo`)\n- Callback stabilization (`useCallback`)\n- Derived state memoization (`useMemo`)\n- Debounced scroll (100ms timeout)\n- Next.js Image (AVIF/WebP with blur placeholder)\n- Tree-shaking (optimized imports)\n- Gzip/Brotli compression\n\n**Metrics** (estimated):\n- First Contentful Paint: \u003c 1.5s\n- Time to Interactive: \u003c 3.5s\n- Cumulative Layout Shift: \u003c 0.1\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.\n\n**Quick start**:\n1. Fork repository\n2. Create feature branch: `git checkout -b feature/name`\n3. Make changes + add Biome checks pass\n4. Commit with [Conventional Commits](https://www.conventionalcommits.org/)\n5. Push and open PR\n\n## License\n\nMIT License - see [LICENSE](./LICENSE)\n\n## Acknowledgments\n\n- [Next.js](https://nextjs.org/) - React framework\n- [Biome](https://biomejs.dev/) - Fast linter \u0026 formatter\n- [shadcn/ui](https://ui.shadcn.com/) - Component system\n- [react-type-animation](https://react-type-animation.netlify.app/) - Typing effects\n- [Google Sheets API](https://developers.google.com/sheets/api) - Data storage\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003csub\u003eBuilt with ❤️ by \u003ca href=\"https://github.com/rafactx\"\u003eRafael Teixeira\u003c/a\u003e\u003c/sub\u003e\n\n**[↑ Back to top](#nextjs-testimonial-form)**\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafactx%2Fnextjs-testimonial-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frafactx%2Fnextjs-testimonial-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafactx%2Fnextjs-testimonial-form/lists"}