Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
bd43b22
feat: add Reward Board link to UserButton and introduce Badge and Use…
Riot-pls Jul 20, 2025
8989089
feat: add line clamp utilities and enhance RewardBoard component with…
Riot-pls Jul 31, 2025
45ec8b0
feat: enhance RewardBoard component to filter rewards by type and imp…
Riot-pls Jul 31, 2025
d3acc62
feat: add new routes for certificate retrieval and update dependencies
Riot-pls Aug 8, 2025
2ed70bf
Merge pull request #48 from Voyager-Ship/voyager-ship/badges
sebaxor Aug 8, 2025
ac15a50
feat: enhance quiz functionality by adding completion tracking and ce…
Riot-pls Aug 9, 2025
bec34e8
Merge pull request #49 from Voyager-Ship/voyager-ship/badges
sebaxor Aug 9, 2025
7f049ef
fix: standardize array syntax in rewardBoard service and clean up cod…
Riot-pls Aug 15, 2025
fcf1af3
Merge branch 'ava-labs:master' into voyager-ship/hackathons-platform
SebasianDev Aug 15, 2025
f252991
refactor: replace SubmissionWrapper with SubmissionWrapperSecure in p…
Aug 16, 2025
8f06564
refactor: clean up code and improve project submission context
Riot-pls Aug 17, 2025
5b97795
Merge pull request #50 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 18, 2025
14c4f3c
refactor: simplify project submission logic and enhance data handling
Riot-pls Aug 18, 2025
ac2e5fd
refactor: enhance form validation and data handling in submission form
Riot-pls Aug 18, 2025
e82c56c
Merge pull request #51 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 18, 2025
73469da
refactor: enhance invitation process and improve error handling
Riot-pls Aug 18, 2025
41426e6
Merge pull request #52 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 19, 2025
f3a5e75
refactor: improve dialog handling and invitation logic
Riot-pls Aug 21, 2025
efd1bc6
refactor: optimize progress calculation in GeneralSecure component
Riot-pls Aug 21, 2025
5b7fda0
refactor: enhance hackathon validation and data handling
Riot-pls Aug 21, 2025
cbafc6c
Merge pull request #53 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 21, 2025
4890e71
refactor: comment out Reward Board link in UserButton component
Riot-pls Aug 21, 2025
18251e8
Merge branch 'voyager-ship/hackathons-platform' into voyager-ship/badges
Riot-pls Aug 21, 2025
bb183d2
Merge pull request #54 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 21, 2025
ff80b96
Merge branch 'master' into voyager-ship/hackathons-platform
sebaxor Aug 22, 2025
9fd877a
feat: add modal for new user profile completion and enhance reward bo…
Riot-pls Aug 22, 2025
66705e1
refactor: update validation messages and improve link handling in sub…
Riot-pls Aug 22, 2025
eb50f16
Merge pull request #55 from Voyager-Ship/voyager-ship/bugfix-project-…
sebaxor Aug 22, 2025
17552e1
refactor: update badge service and components for improved functionality
Riot-pls Aug 25, 2025
7cce7cc
feat: integrate user badges into project overview and team members co…
Riot-pls Aug 25, 2025
b931dbf
style: update styling and layout for reward and member badge components
Aug 25, 2025
9ee31b5
refactor: update MemberBadge layout for improved user experience
Riot-pls Aug 26, 2025
28c8d34
feat: enhance MemberBadge component with badge display toggle and imp…
Riot-pls Aug 26, 2025
9b7ef09
Merge branch 'voyager-ship/hackathons-platform' into voyager-ship/badges
Riot-pls Aug 26, 2025
848e623
feat: enhance RewardBoard and RewardCard components for better user e…
Riot-pls Aug 29, 2025
9a3c336
fix: enhance email input handling in Members component
Riot-pls Aug 29, 2025
031dccf
Merge pull request #56 from Voyager-Ship/voyager-ship/badges
sebaxor Sep 2, 2025
5d27cf7
feat: enhance badge handling and display in RewardBoard and related c…
Riot-pls Sep 3, 2025
6724775
style: improve layout and styling in BadgeNotification component
Riot-pls Sep 3, 2025
3fbb117
Merge pull request #57 from Voyager-Ship/voyager-ship/badges
sebaxor Sep 3, 2025
2fe259f
feat: enhance badge assignment functionality and introduce BadgeCategory
Riot-pls Sep 9, 2025
03563a3
feat: improve badge assignment logic and error handling
Riot-pls Sep 9, 2025
0a8a4cb
refactor: remove deprecated badge assignment routes and enhance badge…
Riot-pls Sep 9, 2025
1d6c847
refactor: remove deprecated badge assignment routes and enhance badge…
Riot-pls Sep 9, 2025
bba0c76
Merge pull request #58 from Voyager-Ship/voyager-ship/fix_strategy
sebaxor Sep 9, 2025
6157f26
feat: add validation for project_id and IsWinner parameters in set-wi…
Riot-pls Sep 9, 2025
25799f5
fix: update return value in BadgeAssignmentService to use BadgeCatego…
Riot-pls Sep 9, 2025
0f14aa0
Merge pull request #59 from Voyager-Ship/voyager-ship/fix_strategy
sebaxor Sep 9, 2025
bd92ca7
refactor: update badge assignment logic and schema
Riot-pls Sep 10, 2025
438bb50
Merge pull request #60 from Voyager-Ship/voyager-ship/fix_strategy
sebaxor Sep 10, 2025
e041206
fix: remove unnecessary fields in badge assignment transactions
Riot-pls Sep 10, 2025
617150c
Merge pull request #61 from Voyager-Ship/voyager-ship/fix_strategy
sebaxor Sep 10, 2025
0a8a157
refactor: update role permissions and clean up badge assignment logic
Riot-pls Sep 13, 2025
a70d5f7
feat: enhance RewardCard component with points calculation and separator
Riot-pls Sep 13, 2025
e5db04a
Merge pull request #62 from Voyager-Ship/badges_bgfix
sebaxor Sep 14, 2025
d08b0f2
Merge branch 'master' into voyager-ship/hackathons-platform
sebaxor Sep 14, 2025
55577b7
choring: prisma
sebaxor Sep 14, 2025
7298502
fix: package.json
sebaxor Sep 14, 2025
65778ab
merge: code merged
sebaxor Sep 14, 2025
7fc417c
feat: implement UserNotRegistered component and integrate with Submis…
Riot-pls Sep 15, 2025
09b63ce
Revert "choring: prisma"
Riot-pls Sep 15, 2025
fec62f1
Merge pull request #63 from Voyager-Ship/bgfix_navigate_registerform
SebasianDev Sep 15, 2025
661d54e
Merge branch 'master' into bgfix_navigate_registerform
Riot-pls Sep 15, 2025
eec489f
feat: add AwardBadgeWrapper component import to certificates.tsx
Riot-pls Sep 15, 2025
8675fb7
Merge branch 'voyager-ship/hackathons-platform' into bgfix_navigate_r…
Riot-pls Sep 16, 2025
d384dd0
fix: update date-fns and react-day-picker dependencies to use version…
Riot-pls Sep 16, 2025
863c855
refactor: consolidate calendar icon components into a single Chevron …
Riot-pls Sep 16, 2025
463934c
fix merge conflict and build errros
navillanueva Sep 16, 2025
7326e5f
Merge pull request #64 from Voyager-Ship/bgfix_navigate_registerform
sebaxor Sep 16, 2025
d5e1b79
Merge remote-tracking branch 'origin/voyager-ship/hackathons-platform…
sebaxor Sep 17, 2025
57313a6
feat: integrate 3D rendering for reward cards using React Three Fiber…
Riot-pls Sep 17, 2025
3d8f108
Merge branch 'master' into voyager-ship/hackathons-platform
SebasianDev Sep 17, 2025
03a5215
refactor: simplify BackFace component and enhance RewardCard layout w…
Riot-pls Sep 17, 2025
39fb72f
refactor: remove unused CSS for reward card and optimize BackFace ren…
Riot-pls Sep 17, 2025
1293f53
Merge remote-tracking branch 'origin/master' into pr-2927
navillanueva Sep 18, 2025
95f06ef
refactor: streamline RewardCard component by removing unused imports …
Riot-pls Sep 19, 2025
e32047d
refactor: enhance ProjectCard component with improved click handling …
Riot-pls Sep 20, 2025
be9ae73
refactor: update project winner handling and enhance badge assignment…
Riot-pls Sep 20, 2025
404c40b
Merge branch 'voyager-ship/hackathons-platform' into badge_card_drag
Riot-pls Sep 20, 2025
2a573b2
refactor: enhance RequirementsPanel component with visual indicators …
Riot-pls Sep 22, 2025
b4360a6
Merge pull request #66 from Voyager-Ship/badge_card_drag
sebaxor Sep 22, 2025
84bc527
refactor: filter badges by category in AssignBadge component for impr…
Riot-pls Sep 24, 2025
0ceeb7d
Merge branch 'master' into pr-2927
Andyvargtz Sep 25, 2025
cfdbc7d
Merge branch 'master' into voyager-ship/hackathons-platform
Riot-pls Sep 26, 2025
38693a0
Merge branch 'master' into badge_card_drag
Riot-pls Sep 26, 2025
659d419
fix: format import statement in certificates.tsx for consistency
Riot-pls Sep 26, 2025
379fc4e
Merge pull request #67 from Voyager-Ship/badge_card_drag
sebaxor Sep 26, 2025
bedf27c
fix: add missing prisma migrations
Andyvargtz Sep 29, 2025
71c930b
Merge branch 'voyager-ship/hackathons-platform' of https://github.com…
Riot-pls Sep 29, 2025
875b49e
Merge branch 'ava-labs:master' into voyager-ship/hackathons-platform
SebasianDev Oct 2, 2025
ad0dc4b
Merge pull request #2927 from Voyager-Ship/voyager-ship/hackathons-pl…
Andyvargtz Oct 3, 2025
cf8289f
Merge remote-tracking branch 'origin/master' into Staging_badges
Andyvargtz Oct 15, 2025
a5501d9
Merge remote-tracking branch 'origin/Fix-migrations' into Staging_badges
Andyvargtz Oct 15, 2025
6d5aa39
merge master into branch
navillanueva Oct 23, 2025
4e57d47
Update package dependencies and enhance ShowCaseCard component with e…
SebasianDev Oct 29, 2025
62ef66a
chore: verified signature - FINAL FIX
SebasianDev Oct 29, 2025
8938f3e
chore: enable verified SSH signing
SebasianDev Oct 29, 2025
d460af4
Enhance AutoRotateMedal and StaticMedal components to support dynamic…
SebasianDev Oct 30, 2025
c6bc78b
Merge branch 'master' into Staging_badges
Andyvargtz Nov 3, 2025
1c09286
Refactor RewardBoard and RequirementsPanel components for improved la…
SebasianDev Nov 4, 2025
ce4399b
Enhance Info component to support multiple demo and GitHub links
SebasianDev Nov 5, 2025
1767734
Merge branch 'staging_badges' into voyager-ship/improvements
SebasianDev Nov 5, 2025
7731900
comment out point system for badges requirements
katherineavalabs Nov 5, 2025
1068925
Update RewardBoard layout and refine badge metadata handling
SebasianDev Nov 6, 2025
2e6bb12
Refactor RewardBoard component and badge metadata processing
SebasianDev Nov 6, 2025
22afbfd
Remove title attribute from RewardCard component for cleaner code
SebasianDev Nov 6, 2025
a84594f
Merge pull request #3265 from Voyager-Ship/voyager-ship/improvements
Andyvargtz Nov 6, 2025
3f92c3b
Update yarn.lock and refactor reward board components
SebasianDev Nov 7, 2025
ae8b20b
Refactor project export functionality and enhance showcase card
SebasianDev Nov 7, 2025
fa9bf20
Enhance RequirementsPanel and RewardCard components with title support
SebasianDev Nov 7, 2025
b0cda97
Refine RequirementsPanel header styling for improved layout
SebasianDev Nov 7, 2025
d193687
Merge pull request #3293 from Voyager-Ship/voyager-ship/improvements
Andyvargtz Nov 7, 2025
5c9a617
Merge branch 'Staging_badges' into badges-comment-out-point-system
katherineavalabs Nov 11, 2025
68783ac
commented out hackathon badges logic and changed rewards to achieveme…
katherineavalabs Nov 12, 2025
66775f5
Merge branch 'badges-comment-out-point-system' of https://github.com/…
katherineavalabs Nov 12, 2025
e710ae3
fix leave commented
katherineavalabs Nov 12, 2025
68d0172
Merge pull request #3271 from ava-labs/badges-comment-out-point-system
katherineavalabs Nov 12, 2025
c4ef66c
Merge branch 'master' into Staging_badges
katherineavalabs Nov 14, 2025
99caf30
versions updated
katherineavalabs Nov 14, 2025
72ef767
Merge branch 'master' into Staging_badges
katherineavalabs Nov 14, 2025
4295989
handling badges with multiple requirements
katherineavalabs Nov 14, 2025
5654ba8
Merge branch 'master' into Staging_badges
navillanueva Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions app/(home)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import type { ReactNode } from "react";
import { Footer } from "@/components/navigation/footer";
import { baseOptions } from "@/app/layout.config";
import { SessionProvider, useSession } from "next-auth/react";
import { useEffect, Suspense } from "react";
import { useEffect, Suspense, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import Modal from "@/components/ui/Modal";
import { Button } from "@/components/ui/button";
import { LayoutWrapper } from "@/app/layout-wrapper.client";
import { NavbarDropdownInjector } from "@/components/navigation/navbar-dropdown-injector";

Expand Down Expand Up @@ -33,6 +35,7 @@ function RedirectIfNewUser() {
const pathname = usePathname();
const router = useRouter();
const searchParams = useSearchParams();
const [showModal, setShowModal] = useState(false);

useEffect(() => {
if (
Expand All @@ -45,9 +48,38 @@ function RedirectIfNewUser() {
if (typeof window !== "undefined") {
localStorage.setItem("redirectAfterProfile", originalUrl);
}

// Show confirmation modal and redirect immediately
setShowModal(true);
router.replace("/profile");
}
}, [session, status, pathname, router, searchParams]);

return null;
const handleContinue = () => {
setShowModal(false);
};

return (
<>
{showModal && (
<Modal
className="border border-red-500"
isOpen={showModal}
onOpenChange={setShowModal}
title="Complete your profile"
description="Please fill your profile information to continue. This will help us provide you with a better experience."
footer={
<div className="flex gap-3 w-full">
<Button
onClick={handleContinue}
className="flex-1"
>
Continue
</Button>
</div>
}
/>
)}
</>
);
}
5 changes: 4 additions & 1 deletion app/(home)/showcase/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import React from "react";
import ProjectOverview from "../../../../components/showcase/ProjectOverview";
import { getProject } from "@/server/services/projects";
import { Project } from "@/types/showcase";
import { getProjectBadges, getUserBadgesByProjectId } from "@/server/services/project-badge";
export default async function ProjectPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const project = await getProject(id);
const badges = await getUserBadgesByProjectId(id);

return (
<main className="container relative max-w-[1400px] pb-16">
<ProjectOverview project={project as unknown as Project} />
<ProjectOverview project={project as unknown as Project} badges={badges} />
</main>
);
}
48 changes: 48 additions & 0 deletions app/api/badge/assign/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { withAuth } from "@/lib/protectedRoute";
import { badgeAssignmentService } from "@/server/services/badgeAssignmentService";
import { getAuthSession } from "@/lib/auth/authSession";

import { NextRequest, NextResponse } from "next/server";

export const POST = withAuth(async (req: NextRequest) => {
try {
const body = await req.json();
const session = await getAuthSession();

// Check authorization based on badge type
const userRole = session?.user.role || "user";
const customAttributes = session?.user.custom_attributes??[];
const hasPermission = badgeAssignmentService.hasRequiredRole(body, customAttributes);

if (!hasPermission) {
const requiredRole = badgeAssignmentService.getRequiredRoleForAssignment(body);
return NextResponse.json(
{
error: {
message: `Insufficient permissions. Required role: ${requiredRole || 'none'}, User role: ${userRole}`
}
},
{ status: 403 }
);
}

// Use the user's name as awardedBy
const badge = await badgeAssignmentService.assignBadge(body, session?.user.name || undefined);

return NextResponse.json({ result: badge }, { status: 200 });
} catch (error: any) {
console.error('Error POST /api/badge/assign:', error.message);
const wrappedError = error as Error;
return NextResponse.json(
{
error: {
message: wrappedError.message,
stack: wrappedError.stack,
cause: wrappedError.cause,
name: wrappedError.name,
},
},
{ status: wrappedError.cause == "ValidationError" ? 400 : 500 }
);
}
});
17 changes: 17 additions & 0 deletions app/api/badge/get-all/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { withAuth } from "@/lib/protectedRoute";
import { getAllBadges, getBadgeByCourseId } from "@/server/services/badge";

import { NextResponse } from "next/server";

export const GET = withAuth(async () => {
try {
const badges = await getAllBadges();
return NextResponse.json(badges, { status: 200 });
} catch (error) {
console.error("Error getting badge:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
});
27 changes: 27 additions & 0 deletions app/api/badge/project-badge/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { withAuth } from "@/lib/protectedRoute";

import { getProjectBadges } from "@/server/services/project-badge";

import { NextResponse } from "next/server";

export const GET = withAuth(async (request) => {
const { searchParams } = new URL(request.url);
const project_id = searchParams.get("project_id");
if (!project_id) {
return NextResponse.json(
{ error: "project_id parameter is required" },
{ status: 400 }
);
}

try {
const badge = await getProjectBadges(project_id);
return NextResponse.json(badge, { status: 200 });
} catch (error) {
console.error("Error getting badge:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
});
3 changes: 2 additions & 1 deletion app/api/badge/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { withAuth } from "@/lib/protectedRoute";
import { getBadgeByCourseId } from "@/server/services/rewardBoard";
import { getBadgeByCourseId } from "@/server/services/badge";

import { NextResponse } from "next/server";

export const GET = withAuth(async (request) => {
Expand Down
33 changes: 33 additions & 0 deletions app/api/badge/validate/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { withAuth } from "@/lib/protectedRoute";
import { getBadgeByCourseId } from "@/server/services/badge";

import { NextResponse } from "next/server";

export const GET = withAuth(async (request) => {
const { searchParams } = new URL(request.url);
const course_id = searchParams.get("course_id");
const user_id = searchParams.get("user_id");
if (!course_id) {
return NextResponse.json(
{ error: "course_id parameter is required" },
{ status: 400 }
);
}
if (!user_id) {
return NextResponse.json(
{ error: "user_id parameter is required" },
{ status: 400 }
);
}

try {
const badge = await getBadgeByCourseId(course_id);
return NextResponse.json(badge, { status: 200 });
} catch (error) {
console.error("Error getting badge:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
});
34 changes: 34 additions & 0 deletions app/api/project/set-winner/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { getAuthSession } from "@/lib/auth/authSession";
import { withAuthRole } from "@/lib/protectedRoute";
import { SetWinner } from "@/server/services/set-project-winner";
import { NextRequest, NextResponse } from "next/server";

export const PUT = withAuthRole("badge_admin", async (req: NextRequest) => {
const body = await req.json();
const session = await getAuthSession();
const name = session?.user.name || "user";

try {
if (!body.project_id) {
return NextResponse.json(
{ error: "project_id parameter is required" },
{ status: 400 }
);
}
if (!body.isWinner) {
return NextResponse.json(
{ error: "IsWinner parameter is required" },
{ status: 400 }
);
}
const badge = await SetWinner(body.project_id, body.isWinner, name);

return NextResponse.json(badge, { status: 200 });
} catch (error) {
console.error("Error checking user by email:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
});
33 changes: 33 additions & 0 deletions app/api/projects/export/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { withAuthRole } from "@/lib/protectedRoute";
import { exportShowcase } from "@/server/services/exportShowcase";
import { NextRequest, NextResponse } from "next/server";

export const POST = withAuthRole('hackathonCreator', async (req: NextRequest) => {
try {
const body = await req.json();
const buffer = await exportShowcase(body);
if (!buffer) {
return NextResponse.json(
{ message: 'No projects found' },
{ status: 404 }
);
}
return new NextResponse(buffer, {
headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
});
} catch (error: any) {
console.error('Error POST /api/projects/export:', error.message);
const wrappedError = error as Error;
return NextResponse.json(
{
error: {
message: wrappedError.message,
stack: wrappedError.stack,
cause: wrappedError.cause,
name: wrappedError.name
}
},
{ status: wrappedError.cause == 'ValidationError' ? 400 : 500 }
);
}
});
47 changes: 0 additions & 47 deletions components/hackathons/project-submission/General.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
'use client';
"use client";

import React from 'react';
import { ProjectSubmissionProvider } from './context/ProjectSubmissionContext';
import GeneralSecureComponent from './components/GeneralSecure';
import React, { useState } from "react";
import { ProjectSubmissionProvider } from "./context/ProjectSubmissionContext";
import GeneralSecureComponent from "./components/GeneralSecure";
import { UserNotRegistered } from "./components/UserNotRegistered";

export function SubmissionWrapperSecure({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const [showComponent, setShowComponent] = useState(false);

const handleShowComponent = (show: boolean) => {
setShowComponent(show);
};

return (
<ProjectSubmissionProvider>
<GeneralSecureComponent searchParams={searchParams} />
{!showComponent && (
<UserNotRegistered
hackathonId={searchParams.hackathon as string}
onToggle={handleShowComponent}
/>
)}
{showComponent && <GeneralSecureComponent searchParams={searchParams} />}
</ProjectSubmissionProvider>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert";
import { JoinTeamDialog } from "./JoinTeamDialog";
import { ProjectMemberWarningDialog } from "./ProjectMemberWarningDialog";
import InvalidInvitationComponent from "./InvalidInvitationDialog";
import Modal from "@/components/ui/Modal";

export default function GeneralSecureComponent({
searchParams,
Expand Down Expand Up @@ -335,7 +336,6 @@ export default function GeneralSecureComponent({
dispatch({ type: "SET_OPEN_INVALID_INVITATION", payload: open })
}
/>

{error && (
<div className="mt-4">
<Alert variant="destructive">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export default function MembersComponent({
spellCheck="false"
onChange={(e) => setNewEmail(e.target.value)}
onKeyDown={async (e) => {
if (e.key === "Enter" || e.key === " ") {
if (e.key === "Enter" || e.key === " " || e.key === "Tab") {
e.preventDefault();
await handleAddEmail();
}
Expand Down
Loading