-
-
Notifications
You must be signed in to change notification settings - Fork 2
Feat: Integrate Auth (supabase) + UI user pages #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
e3eb38c
chore: update README to include TODOs
alexmarqs f1a05c3
feat (wip): start integrating supabase + user menu, settings page
alexmarqs 7e6030a
feat: integrate Sonner for toast notifications and enhance user profi…
alexmarqs 9d0fd70
refactor: clean up imports and remove unused components in layout and…
alexmarqs 4a81b33
chore: enhance form handling in AccountName component with validation…
alexmarqs 2b08271
refactor: simplify form submission logic in AccountName component and…
alexmarqs d5393af
refactor: update DeleteAccount component layout and styling for impro…
alexmarqs 40e2ff4
chore: update dependencies and improve CI workflow for better perform…
alexmarqs c6363f7
feat: implement alert dialog for account deletion and update dependen…
alexmarqs cb23602
feat: add logo to login page and refactor search query params usage a…
alexmarqs e88a273
feat: integrate session management in UserMenu component and enhance …
alexmarqs 3e4a65c
feat: wrap GoHomeLoginButton in Suspense due to usage of search params
alexmarqs 6857a94
feat: enhance user profile mutation with success and error notificati…
alexmarqs 4fdcaf6
fix: update label in SearchSideBar component from "Search term" to "S…
alexmarqs c6bcb4f
wip: implement avatar upload functionality in AccountAvatar component…
alexmarqs 2bdb1e3
feat: enhance AccountAvatar component with file upload handling, prev…
alexmarqs 80bd37d
feat: implement user deletion API and enhance AccountAvatar and UserM…
alexmarqs c339ad4
chore: update .env.example to include missing placeholders SUPABASE_S…
alexmarqs 8d0e7c2
chore: update db:types command in package.json for improved dotenv us…
alexmarqs 2af814c
fix: improve avatar handling in UserMenu and AccountAvatar components…
alexmarqs c788a05
feat: add email components for welcome and footer sections, update pa…
alexmarqs 17ef619
chore: add CLAUDE.md to .gitignore to prevent tracking of the file
alexmarqs ad64840
chore: update @react-email/preview-server dependency to version 4.2.8…
alexmarqs 834ba74
chore: update .gitignore to include AGENTS.md and retain CLAUDE.md
alexmarqs cc9f366
feat: integrate Plunk email service, add email utility functions, and…
alexmarqs 9d4f148
feat: add welcome email functionality and integrate @vercel/functions…
alexmarqs 403798b
refactor: remove unused email type and subscription fields from email…
alexmarqs 1b5b179
feat: add Google login component to the login page
alexmarqs f92579d
refactor: simplify CompaniesList component by removing updatedAtISODa…
alexmarqs f12afcc
test: add mock Supabase environment variables for Playwright testing …
alexmarqs 55ccb5c
chore: update CI workflow to include additional Supabase environment …
alexmarqs 587f7c8
fix: increase loading timeout in GithubLogin and GoogleLogin componen…
alexmarqs 97262a4
feat: add static GET route for generating llms.txt with company, cate…
alexmarqs 105b831
feat: integrate analytics tracking for user interactions in FeaturedS…
alexmarqs 767e442
feat: replace button in FeaturedSideSection with RequestFeaturedButto…
alexmarqs f45ad50
feat: enhance image handling in Next.js config and add analytics trac…
alexmarqs c4280b2
fix: improve loading state management in GithubLogin and GoogleLogin …
alexmarqs 4cea79c
fix: correct Supabase URL assignment in CI workflow and simplify data…
alexmarqs 7eb356c
fix: update GitHub repository links and improve error handling in ema…
alexmarqs 7aea44b
feat: enhance BackButton component with browser history navigation an…
alexmarqs 78dabd4
fix: correct typo in welcome email template for notifications
alexmarqs 3b1b4d2
fix: ensure router replace for logout is consistently called in UserM…
alexmarqs 1ef59eb
fix: revoke blob URL on unmount in AccountAvatar component to prevent…
alexmarqs e9031a7
fix: remove unnecessary remote pattern for Supabase images in Next.js…
alexmarqs 5ab6549
feat: add contact form functionality with email sending capability an…
alexmarqs 3ffcd52
fix: restrict ContactButton visibility based on user authentication s…
alexmarqs 0cec3e6
feat: implement PWA support with install banner and manifest for enha…
alexmarqs 34b163f
feat: update ContactButton UI and enhance error handling in contact f…
alexmarqs fd77dbb
feat: enhance contact form validation and improve email sending logic…
alexmarqs ab1ff30
fix: update footer text from "Crafted by" to "Built by" and adjust re…
alexmarqs da13352
fix: remove unused size prop from FiltersButton component
alexmarqs 988e7c0
fix: update rate limiting TODO comments in sendContactMessageAction a…
alexmarqs 5bf4c38
fix: update PWAInstallBanner to prevent prompt from showing if dismis…
alexmarqs 38cf584
fix: update manifest and PWAInstallBanner for improved functionality …
alexmarqs a63f178
docs: update README to enhance PWA support description and add LLMs.t…
alexmarqs 4a682de
refactor: remove react-countup dependency and update email formatting…
alexmarqs f79204d
feat: integrate Arcjet for rate limiting in contact form submissions …
alexmarqs df73c6b
refactor: simplify PWAInstallBanner logic for dismissing prompts and …
alexmarqs 3dd0ca3
fix: escape user messages in sendContactMessageAction to prevent XSS …
alexmarqs 2bccec8
fix: remove TODO comment for rate limiting in auth callback route
alexmarqs 361a567
docs: add Arcjet reference for rate limiting in README
alexmarqs 685ade3
docs: update README to provide a clearer monorepo structure overview
alexmarqs 985e546
docs: remove redundant line from README regarding monorepo structure
alexmarqs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,12 @@ | ||
| # For turbo builds, prefixes with NEXT_PUBLIC_ are automatically considered to force a rebuild | ||
| NEXT_PUBLIC_POSTHOG_KEY= | ||
| NEXT_PUBLIC_POSTHOG_HOST= | ||
| NEXT_PUBLIC_POSTHOG_HOST= | ||
| NEXT_PUBLIC_SUPABASE_URL= | ||
| # Make sure to enable RLS and policies to use this key in client | ||
| NEXT_PUBLIC_SUPABASE_ANON_KEY= | ||
| SUPABASE_SERVICE_ROLE_KEY= | ||
| SUPABASE_URL= | ||
| PLUNK_API_KEY= | ||
| CONTACT_FROM_EMAIL= | ||
| CONTACT_TO_EMAIL= | ||
| ARCJET_KEY= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| "use server"; | ||
|
|
||
| import { emailService } from "@/lib/email"; | ||
| import { createClient } from "@/lib/supabase/server"; | ||
| import arcjet, { request, slidingWindow } from "@arcjet/next"; | ||
|
|
||
| // Per user rate limiter: 3 requests per day per user. | ||
| // This is to prevent abuse of the contact form. | ||
| const rateLimiter = arcjet({ | ||
| key: process.env.ARCJET_KEY!, | ||
| rules: [ | ||
| slidingWindow({ | ||
| mode: "LIVE", // will block requests. Use "DRY_RUN" to log only | ||
| characteristics: ["userId"], | ||
| interval: "24h", // 24 hour sliding window | ||
| max: 3, // allow a maximum of 3 requests per day per IP address | ||
| }), | ||
| ], | ||
| }); | ||
alexmarqs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export const sendContactMessageAction = async (formData: FormData) => { | ||
| const supabase = await createClient(); | ||
|
|
||
| // Get the authenticated user's email from the server session | ||
| const { | ||
| data: { user }, | ||
| error, | ||
| } = await supabase.auth.getUser(); | ||
|
|
||
| if (error || !user?.email) { | ||
| throw new Error("User not authenticated"); | ||
| } | ||
|
|
||
| const req = await request(); | ||
| const decision = await rateLimiter.protect(req, { userId: user.id }); | ||
|
|
||
| if (decision.isDenied()) | ||
| throw new Error("Rate limit exceeded. Please try again later."); | ||
|
|
||
| const message = formData.get("message")?.toString().trim(); | ||
|
|
||
| if (!message || message.length === 0) { | ||
| throw new Error("Message is required"); | ||
| } | ||
|
|
||
| const escapedMessage = escapeString(message); | ||
| const fromEmail = process.env.CONTACT_FROM_EMAIL; | ||
| const toEmail = process.env.CONTACT_TO_EMAIL; | ||
|
|
||
| if (!fromEmail || !toEmail) { | ||
| throw new Error("Email configuration is missing"); | ||
| } | ||
|
|
||
| const firstPartEmail = user.email.split("@")[0]; | ||
|
|
||
| await emailService.sendEmail({ | ||
| from: fromEmail, | ||
| name: "Tech Companies Portugal", | ||
| subject: "New message received — Tech Companies Portugal", | ||
| body: ` | ||
| <p>Hello 👋</p> | ||
| <p>You have received a new message through the <strong>Tech Companies Portugal</strong> website.</p> | ||
|
|
||
| <p><strong>From:</strong> ${firstPartEmail}</p> | ||
|
|
||
| <p><strong>Message:</strong></p> | ||
| <blockquote style="border-left:3px solid #ccc;padding-left:8px;margin:10px 0;"> | ||
| <p>${escapedMessage}</p> | ||
| </blockquote> | ||
|
|
||
| <hr> | ||
| <p style="font-size:12px;color:#666;"> | ||
| Automated message from Tech Companies Portugal — ${new Date().toLocaleDateString()}. | ||
| </p> | ||
| `, | ||
| to: toEmail, | ||
| }); | ||
alexmarqs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return { success: true }; | ||
| }; | ||
|
|
||
| // Escape a string to prevent XSS attacks | ||
| const escapeString = (str: string) => { | ||
| return str | ||
| .replace(/&/g, "&") | ||
| .replace(/</g, "<") | ||
| .replace(/>/g, ">") | ||
| .replace(/"/g, """) | ||
| .replace(/'/g, "'"); | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.