feat: add country flag to region-locked tracks (fixes #1354)#1415
feat: add country flag to region-locked tracks (fixes #1354)#1415espadondutravail wants to merge 1 commit into
Conversation
|
@espadondutravail is attempting to deploy a commit to the Superteam Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Review limit reached
More reviews will be available in 20 minutes and 53 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
WalkthroughThe PR adds ChangesRegion-locked track flag display
MariaDB Prisma adapter setup
Sequence Diagram(s)sequenceDiagram
participant API as API Endpoint
participant TrackBox
participant UserFlag
API->>TrackBox: Returns sponsor.chapter.code, sponsor.chapter.name
TrackBox->>TrackBox: Check if sponsor.chapter.code exists
alt chapter.code defined
TrackBox->>UserFlag: Pass location=code, isCode, ...rest div attrs
UserFlag->>UserFlag: Merge ...rest className and style into computed styles
TrackBox->>TrackBox: Render flex row: sponsor.name + flag + "chapter.name Only" pill
else chapter.code undefined
TrackBox->>TrackBox: Render flex row: sponsor.name only
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/interface/hackathon.ts (1)
9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse explicit
| undefinedfor new chapter fields instead of optional props.These new shared-contract fields should follow the project typing rule to avoid omission-by-default object shapes in consumers.
♻️ Suggested change
- code?: string; - name?: string; + code: string | undefined; + name: string | undefined;As per coding guidelines,
**/*.{ts,tsx}: Useproperty: Type | undefinedinstead ofproperty?: Typefor TypeScript type definitions to force explicit property passing and prevent bugs from accidentally omitting required properties.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/interface/hackathon.ts` around lines 9 - 10, The fields code and name in the shared-contract type definition are using optional property syntax (property?: Type) instead of the project's required explicit undefined syntax (property: Type | undefined). Convert both the code and name fields from optional properties with the `?` modifier to explicit union types with undefined to enforce explicit property passing and align with the project's TypeScript typing guidelines.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/hackathon/TrackBox.tsx`:
- Around line 31-41: The chapter pill is currently guarded only on the existence
of sponsor?.chapter?.code, but the rendered content also uses
sponsor?.chapter?.name. Update the conditional check to verify that both
sponsor?.chapter?.code AND sponsor?.chapter?.name exist before rendering the
entire span element to prevent displaying an incomplete label when the name is
missing.
In `@src/components/shared/UserFlag.tsx`:
- Line 27: Remove the `alt` prop from the `Props` interface in the UserFlag
component since the `alt` attribute has no effect on `<div>` elements and
creates a misleading API. Instead, provide proper accessibility attributes based
on the flag's purpose: use `aria-hidden="true"` when the flag is decorative, or
use `role="img"` combined with `aria-label` when the flag should be announced to
screen readers. This ensures the component API is clear and the accessibility
implementation is correct for the div-based rendering approach.
---
Nitpick comments:
In `@src/interface/hackathon.ts`:
- Around line 9-10: The fields code and name in the shared-contract type
definition are using optional property syntax (property?: Type) instead of the
project's required explicit undefined syntax (property: Type | undefined).
Convert both the code and name fields from optional properties with the `?`
modifier to explicit union types with undefined to enforce explicit property
passing and align with the project's TypeScript typing guidelines.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 95eb51e3-1bfd-4614-8093-0592dc71a39c
📒 Files selected for processing (4)
src/components/hackathon/TrackBox.tsxsrc/components/shared/UserFlag.tsxsrc/interface/hackathon.tssrc/pages/api/hackathon/[slug].ts
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/prisma.ts`:
- Around line 34-35: The new URL constructor call in the databaseUrl processing
logic throws an opaque TypeError when databaseUrl is empty, since it defaults to
an empty string. Add a validation guard before the new URL(databaseUrl)
instantiation that checks if databaseUrl is empty or falsy, and throw a clear,
descriptive error message explaining that DATABASE_URL must be set and valid
instead of allowing the URL constructor to throw its generic TypeError. This
will provide developers with actionable feedback when the environment variable
is missing.
- Around line 35-41: The URL components returned from the WHATWG URL API are
percent-encoded, and passing them directly to the PrismaMariaDb constructor with
encoded special characters causes authentication and database lookup failures.
Wrap the url.username, url.password, and the database name (from
url.pathname.slice(1)) with decodeURIComponent() to properly decode any reserved
characters. Additionally, update the parseInt call for url.port to include the
radix parameter parseInt(url.port, 10) for explicit decimal parsing instead of
relying on implicit conversion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 966ef3a6-4265-451f-a0ae-60b456cb0229
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
package.jsonsrc/components/hackathon/TrackBox.tsxsrc/components/shared/UserFlag.tsxsrc/prisma.ts
💤 Files with no reviewable changes (1)
- src/components/shared/UserFlag.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/hackathon/TrackBox.tsx
| // Local MySQL/MariaDB — Prisma v7 always requires a driver adapter | ||
| const url = new URL(databaseUrl); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
new URL(databaseUrl) throws when DATABASE_URL is unset.
databaseUrl defaults to '' (Line 17). When unset, isPlanetScale is false, so execution reaches this branch and new URL('') throws a TypeError at module load, crashing every importer of prisma. Consider guarding for an empty/invalid URL with a clear error message instead of an opaque throw.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prisma.ts` around lines 34 - 35, The new URL constructor call in the
databaseUrl processing logic throws an opaque TypeError when databaseUrl is
empty, since it defaults to an empty string. Add a validation guard before the
new URL(databaseUrl) instantiation that checks if databaseUrl is empty or falsy,
and throw a clear, descriptive error message explaining that DATABASE_URL must
be set and valid instead of allowing the URL constructor to throw its generic
TypeError. This will provide developers with actionable feedback when the
environment variable is missing.
| const url = new URL(databaseUrl); | ||
| const adapter = new PrismaMariaDb({ | ||
| host: url.hostname, | ||
| port: parseInt(url.port) || 3306, | ||
| user: url.username || 'root', | ||
| password: url.password || undefined, | ||
| database: url.pathname.slice(1), |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major
🧩 Analysis chain
🌐 Web query:
Does WHATWG URL API percent-encode the username and password components?
💡 Result:
Yes, the WHATWG URL API percent-encodes username and password components [1][2]. When you set the username or password via the URL API (e.g., url.username = "..." or url.password = "..."), the implementation runs the specified input through a UTF-8 percent-encoding process using the "userinfo percent-encode set" [1][3][2]. The userinfo percent-encode set includes a broad range of characters to ensure that credentials are properly represented within a URL structure [4][2]. Specifically, it encodes characters that could interfere with URL parsing or structural integrity, such as "/", ":", ";", "=", "@", "[", "", "]", "^", and "|" [2]. The internal storage of these components in the URL object is kept in a percent-encoded form [5], which simplifies the process of serializing the full URL string [5].
Citations:
- 1: https://url.spec.whatwg.org/commit-snapshots/5fc4c4c17f3077beda5e3647df73f4b1b0ba7084/
- 2: https://url.spec.whatwg.org/commit-snapshots/488c459d9e4245a3f6bf087e7dcd2c7e91487ac5/
- 3: https://rawgit.com/whatwg/url/8be4726f53/url.html
- 4: Percent encoding examples seem to be wrong whatwg/url#895
- 5: Encode ' in username and password whatwg/url#608
🏁 Script executed:
node <<'EOF'
// Test what URL API accessors actually return
const testUrls = [
'mysql://root:pass%40word@localhost:3306/my%2Fdb',
'mysql://user%40domain:pass%3Aword@localhost:3306/db%23name',
'mysql://admin:p%25ss@localhost:3306/db%20name',
];
testUrls.forEach(urlStr => {
console.log(`\nOriginal URL: ${urlStr}`);
const url = new URL(urlStr);
console.log(` url.username: ${url.username}`);
console.log(` url.password: ${url.password}`);
console.log(` url.pathname: ${url.pathname}`);
console.log(` Decoded username: ${decodeURIComponent(url.username)}`);
console.log(` Decoded password: ${decodeURIComponent(url.password)}`);
console.log(` Decoded pathname: ${decodeURIComponent(url.pathname.slice(1))}`);
});
EOFRepository: SuperteamDAO/earn
Length of output: 834
🏁 Script executed:
find . -name "prisma.ts" -type f | head -5Repository: SuperteamDAO/earn
Length of output: 171
🏁 Script executed:
cat -n ./src/prisma.tsRepository: SuperteamDAO/earn
Length of output: 2072
Decode percent-encoded credentials from DATABASE_URL.
URL.username, URL.password, and URL.pathname return percent-encoded values from the WHATWG URL API. Passing them directly to PrismaMariaDb causes any credentials or database name containing reserved characters (e.g., @, :, /, #, space) to be sent encoded, resulting in authentication failures or "unknown database" errors. Decode each component using decodeURIComponent() before use.
Also add the radix parameter to parseInt(url.port, 10) for explicit decimal parsing.
Proposed fix
const url = new URL(databaseUrl);
const adapter = new PrismaMariaDb({
host: url.hostname,
- port: parseInt(url.port) || 3306,
- user: url.username || 'root',
- password: url.password || undefined,
- database: url.pathname.slice(1),
+ port: parseInt(url.port, 10) || 3306,
+ user: url.username ? decodeURIComponent(url.username) : 'root',
+ password: url.password ? decodeURIComponent(url.password) : undefined,
+ database: decodeURIComponent(url.pathname.slice(1)),
connectionLimit: 5,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const url = new URL(databaseUrl); | |
| const adapter = new PrismaMariaDb({ | |
| host: url.hostname, | |
| port: parseInt(url.port) || 3306, | |
| user: url.username || 'root', | |
| password: url.password || undefined, | |
| database: url.pathname.slice(1), | |
| const url = new URL(databaseUrl); | |
| const adapter = new PrismaMariaDb({ | |
| host: url.hostname, | |
| port: parseInt(url.port, 10) || 3306, | |
| user: url.username ? decodeURIComponent(url.username) : 'root', | |
| password: url.password ? decodeURIComponent(url.password) : undefined, | |
| database: decodeURIComponent(url.pathname.slice(1)), | |
| connectionLimit: 5, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prisma.ts` around lines 35 - 41, The URL components returned from the
WHATWG URL API are percent-encoded, and passing them directly to the
PrismaMariaDb constructor with encoded special characters causes authentication
and database lookup failures. Wrap the url.username, url.password, and the
database name (from url.pathname.slice(1)) with decodeURIComponent() to properly
decode any reserved characters. Additionally, update the parseInt call for
url.port to include the radix parameter parseInt(url.port, 10) for explicit
decimal parsing instead of relying on implicit conversion.
9ebeeff to
246f8c0
Compare
246f8c0 to
2984f99
Compare
What does this PR do?
Adds a country flag and an exclusive label (e.g.,
🇩🇪 Superteam Germany Only) to region-locked tracks on the submission tracks page. This makes it instantly clear at a glance which tracks users are eligible to participate in.Where should the reviewer start?
src/pages/api/hackathon/[slug].ts: Updated the Prisma query to selectchapter.code(ISO string) andchapter.name.src/components/hackathon/TrackBox.tsx: Conditionally rendering theUserFlagand the regional label only ifsponsor.chapter.codeis present.src/components/shared/UserFlag.tsx: Extended props to accept standard HTML attributes (likearia-hiddenandalt) for a11y support.How should this be manually tested?
Any background context you want to provide?
This properly implements the feature requested in #1354.
Note: The previous attempt (PR #1359) failed because it tried to map
chapter.id(which is a UUIDv4) to a country code. This PR correctly useschapter.codewhich already stores the ISO-3166 code in the database.It also ensures strict accessibility (a11y) compliance by passing
aria-hidden="true"andalt=""to the flag so screen readers don't read the country name twice.What are the relevant issues?
Fixes #1354
Screenshots (if appropriate)
(You can leave this blank or drop a quick screenshot of a TrackBox with the flag if you have one!)
Summary by CodeRabbit
New Features
Improvements
Chores