Skip to content

feat: add country flag to region-locked tracks (fixes #1354)#1415

Open
espadondutravail wants to merge 1 commit into
SuperteamDAO:mainfrom
espadondutravail:feat/country-flag-region-locked-tracks-1354
Open

feat: add country flag to region-locked tracks (fixes #1354)#1415
espadondutravail wants to merge 1 commit into
SuperteamDAO:mainfrom
espadondutravail:feat/country-flag-region-locked-tracks-1354

Conversation

@espadondutravail

@espadondutravail espadondutravail commented Jun 23, 2026

Copy link
Copy Markdown

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 select chapter.code (ISO string) and chapter.name.
  • src/components/hackathon/TrackBox.tsx: Conditionally rendering the UserFlag and the regional label only if sponsor.chapter.code is present.
  • src/components/shared/UserFlag.tsx: Extended props to accept standard HTML attributes (like aria-hidden and alt) for a11y support.

How should this be manually tested?

  1. Open a hackathon listing that has both global tracks and region-locked tracks.
  2. Observe that region-locked tracks display the correct country flag and chapter name (e.g., "Superteam UAE Only").
  3. Verify that global tracks (without a chapter or chapter code) remain unchanged.

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 uses chapter.code which already stores the ISO-3166 code in the database.
It also ensures strict accessibility (a11y) compliance by passing aria-hidden="true" and alt="" 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

    • Added chapter indicators next to sponsor names in track information, showing a flag icon and “{chapter name} Only” when chapter code and name are available.
  • Improvements

    • Sponsor chapter data (code and name) is now included in hackathon bounty responses for more complete display.
    • Enhanced flag rendering to support extra HTML attributes for better styling flexibility.
  • Chores

    • Improved Prisma MariaDB adapter setup for more reliable local database connections.

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

@espadondutravail is attempting to deploy a commit to the Superteam Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@espadondutravail, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6dd101f4-eda9-4f29-9da9-ea1cf3e46659

📥 Commits

Reviewing files that changed from the base of the PR and between 323343c and 2984f99.

📒 Files selected for processing (4)
  • src/components/hackathon/TrackBox.tsx
  • src/components/shared/UserFlag.tsx
  • src/interface/hackathon.ts
  • src/pages/api/hackathon/[slug].ts

Walkthrough

The PR adds code and name fields to TrackProps.sponsor.chapter, includes them in the Prisma query for the hackathon slug API endpoint, extends UserFlag to accept and forward arbitrary HTMLDivElement attributes, conditionally renders a country flag pill alongside the sponsor name in TrackBox when a chapter code is present, and configures the MariaDB Prisma adapter for local database connections by parsing credentials from DATABASE_URL.

Changes

Region-locked track flag display

Layer / File(s) Summary
Data contract and API query extension
src/interface/hackathon.ts, src/pages/api/hackathon/[slug].ts
TrackProps.sponsor.chapter gains optional code and name fields; the Prisma findMany select for the hackathon slug endpoint includes both new fields in its chapter projection.
UserFlag attribute forwarding
src/components/shared/UserFlag.tsx
UserFlag's Props now extends React.HTMLAttributes<HTMLDivElement> and the component destructures ...rest, merging className via cn() and style with computed values in both custom-flag and standard-flag branches.
TrackBox region-locked flag pill
src/components/hackathon/TrackBox.tsx
TrackBox imports UserFlag and renders a flex-row sponsor container that always shows sponsor.name and conditionally appends a pill with UserFlag and "{chapter.name} Only" text when sponsor?.chapter?.code is defined.

MariaDB Prisma adapter setup

Layer / File(s) Summary
MariaDB adapter dependency and import
package.json, src/prisma.ts
Adds @prisma/adapter-mariadb@^7.8.0 to dependencies and activates the previously-commented PrismaMariaDb import.
MariaDB adapter initialization
src/prisma.ts
Replaces local (non-PlanetScale) Prisma client setup: parses DATABASE_URL via URL, constructs PrismaMariaDb adapter with hostname, port, username (defaulting to root), password, database name, and fixed connectionLimit, then passes the adapter to new PrismaClient(...).

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • SuperteamDAO/earn#1011: Extends UserFlag component to accept HTML attributes; the main PR's UserFlag changes enable the pill-rendering use case in TrackBox.
  • SuperteamDAO/earn#1291: Both PRs modify src/prisma.ts and Prisma adapter dependencies; the main PR configures MariaDB adapter while the retrieved PR upgrades Prisma to v7 and related adapter packages.

Poem

🐰 A flag now dances, bright and clear,
"Germany Only"—the regions appear!
With ...rest spread far and wide,
UserFlag wears its HTML pride.
MariaDB hops into place at last,
From PlanetScale shadows, the die is cast! 🚩

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The MariaDB adapter addition in package.json and src/prisma.ts appears unrelated to the country flag feature requested in issue #1354. Clarify why the MariaDB adapter changes were included, or move them to a separate PR to keep this PR focused on the region-locked track feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding country flags to region-locked tracks, with a direct reference to the addressed issue.
Linked Issues check ✅ Passed The PR successfully implements all requirements from issue #1354: adding visual country indicators to region-locked tracks using the existing chapter.code field for ISO country codes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/interface/hackathon.ts (1)

9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use explicit | undefined for 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}: Use property: Type | undefined instead of property?: Type for 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1897063 and 650b567.

📒 Files selected for processing (4)
  • src/components/hackathon/TrackBox.tsx
  • src/components/shared/UserFlag.tsx
  • src/interface/hackathon.ts
  • src/pages/api/hackathon/[slug].ts

Comment thread src/components/hackathon/TrackBox.tsx Outdated
Comment thread src/components/shared/UserFlag.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 650b567 and 323343c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • package.json
  • src/components/hackathon/TrackBox.tsx
  • src/components/shared/UserFlag.tsx
  • src/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

Comment thread src/prisma.ts Outdated
Comment on lines +34 to +35
// Local MySQL/MariaDB — Prisma v7 always requires a driver adapter
const url = new URL(databaseUrl);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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.

Comment thread src/prisma.ts Outdated
Comment on lines +35 to +41
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),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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:


🏁 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))}`);
});
EOF

Repository: SuperteamDAO/earn

Length of output: 834


🏁 Script executed:

find . -name "prisma.ts" -type f | head -5

Repository: SuperteamDAO/earn

Length of output: 171


🏁 Script executed:

cat -n ./src/prisma.ts

Repository: 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.

Suggested change
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.

@espadondutravail espadondutravail force-pushed the feat/country-flag-region-locked-tracks-1354 branch 3 times, most recently from 9ebeeff to 246f8c0 Compare June 23, 2026 15:58
@espadondutravail espadondutravail force-pushed the feat/country-flag-region-locked-tracks-1354 branch from 246f8c0 to 2984f99 Compare June 23, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat Req: Add country logo to region locked tracks on submission tracks page.

1 participant