Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
869 changes: 805 additions & 64 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/vite": "^4.2.1",
"lucide-react": "^0.577.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
"react-dom": "^19.2.0",
"recharts": "^3.7.0"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"autoprefixer": "^10.4.27",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"postcss": "^8.5.8",
"tailwindcss": "^4.2.1",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "npm:rolldown-vite@7.2.5"
Expand Down
7 changes: 1 addition & 6 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
/* Styles replaced by Tailwind CSS */
7 changes: 2 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import './App.css'
import Dashboard from './components/Dashboard/Dashboard'

function App() {

return (
<>
<h1>Hello, OrgExplorer!</h1>
</>
<Dashboard />
)
}

Expand Down
57 changes: 57 additions & 0 deletions src/components/Dashboard/ContributorActivity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from 'recharts';

interface ActivityData {
week: string;
commits: number;
}

interface ContributorActivityProps {
data: ActivityData[];
name: string;
}

export const ContributorActivity: React.FC<ContributorActivityProps> = ({ data, name }) => {
return (
<div className="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 h-[300px]">
<h3 className="text-sm font-semibold mb-4 text-gray-800 dark:text-gray-100">
Commit Activity for <span className="text-blue-500">{name}</span>
</h3>
Comment on lines +25 to +27
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Localize contributor activity heading template.

The Commit Activity for ... text is user-visible and currently inline. Externalize the template string to i18n resources (with a variable placeholder for contributor name).

As per coding guidelines, "User-visible strings should be externalized to resource files (i18n)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorActivity.tsx` around lines 25 - 27, The
heading text in the ContributorActivity component is user-visible and must be
externalized; update the component (ContributorActivity) to use the i18n
translation API (e.g., useTranslation or t) and replace the inline template
"Commit Activity for {name}" with a call to the translation key (e.g.,
t('contributorActivity', { name })); add the new key with a variable placeholder
to the locale resource files (e.g., "contributorActivity": "Commit Activity for
{{name}}") and ensure the component imports and uses the translation hook
instead of hardcoding the string.

<ResponsiveContainer width="100%" height="80%">
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" className="dark:stroke-gray-700" />
<XAxis
dataKey="week"
tick={{ fontSize: 10 }}
stroke="#9ca3af"
/>
<YAxis stroke="#9ca3af" tick={{ fontSize: 10 }} />
<Tooltip
contentStyle={{
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderRadius: '8px',
border: 'none',
boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)'
}}
/>
<Line
type="monotone"
dataKey="commits"
stroke="#3b82f6"
strokeWidth={2}
dot={{ r: 3, fill: '#3b82f6' }}
activeDot={{ r: 5 }}
/>
</LineChart>
</ResponsiveContainer>
</div>
);
};
57 changes: 57 additions & 0 deletions src/components/Dashboard/ContributorChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Cell
} from 'recharts';
import type { ContributorData } from './types';

interface ContributorChartProps {
data: ContributorData[];
}

const COLORS = ['#6366f1', '#818cf8', '#a5b4fc', '#c7d2fe', '#e0e7ff'];

export const ContributorChart: React.FC<ContributorChartProps> = ({ data }) => {
return (
<div className="bg-white dark:bg-gray-900 p-6 rounded-xl shadow-sm border border-gray-100 dark:border-gray-800 h-[400px]">
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-100">Top Contributors by Commits</h3>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Externalize contributor chart title.

Line 23 hardcodes the visible title (Top Contributors by Commits). Move it to i18n resource files.

As per coding guidelines, "User-visible strings should be externalized to resource files (i18n)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorChart.tsx` at line 23, The hardcoded
header string in ContributorChart.tsx ("Top Contributors by Commits") must be
externalized to i18n: import and use the project's translation hook (e.g.,
useTranslation or t) in the ContributorChart component and replace the literal
in the <h3> (or its surrounding JSX) with a call to the translation key
(suggested key: dashboard.topContributorsByCommits); then add that key and
translated values to the locale resource files for supported languages so the UI
reads the title from i18n instead of a hardcoded string.

<ResponsiveContainer width="100%" height="90%">
<BarChart
data={data}
layout="vertical"
margin={{ top: 5, right: 30, left: 40, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" horizontal={true} vertical={false} stroke="#e5e7eb" className="dark:stroke-gray-700" />
<XAxis type="number" hide />
<YAxis
dataKey="name"
type="category"
width={100}
tick={{ fontSize: 11, fill: '#9ca3af' }}
stroke="none"
/>
<Tooltip
cursor={{ fill: '#f3f4f6', opacity: 0.1 }}
contentStyle={{
backgroundColor: 'rgba(255, 255, 255, 0.9)',
borderRadius: '8px',
border: 'none',
boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)'
}}
/>
<Bar dataKey="commits" radius={[0, 4, 4, 0]}>
{data.map((_, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
);
};
64 changes: 64 additions & 0 deletions src/components/Dashboard/ContributorModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import { X, Mail, ExternalLink } from 'lucide-react';
import type { ContributorData } from './types';

interface ContributorModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
contributors: ContributorData[];
}

export const ContributorModal: React.FC<ContributorModalProps> = ({ isOpen, onClose, title, contributors }) => {
if (!isOpen) return null;

return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
<div className="bg-white dark:bg-gray-900 w-full max-w-2xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
<div className="p-6 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between">
<div>
<h2 className="text-xl font-bold dark:text-white">{title}</h2>
<p className="text-sm text-gray-500">{contributors.length} contributors found</p>
Comment on lines +20 to +21
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Externalize modal copy to i18n resources.

Strings like contributors found, commits, and Close should be sourced from localization resources, not inline literals.

As per coding guidelines, "User-visible strings should be externalized to resource files (i18n)".

Also applies to: 41-41, 58-58

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorModal.tsx` around lines 20 - 21, The
modal currently uses inline user-visible strings (e.g., the paragraph showing
"{contributors.length} contributors found", the header title prop in
ContributorModal, the "commits" label and the "Close" button text) — replace
these literals with i18n resource lookups: import and use your project's
translation helper (e.g., useTranslation/t) in the ContributorModal component
and swap the inline strings for translation keys (e.g., contributorsFound,
commitsLabel, closeButton) while passing contributors.length and title into the
translated/messages where needed; update the i18n resource files with the new
keys and use the keys in the JSX for the h2, the contributors count <p>, the
commits label, and the Close button.

</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
Comment on lines +23 to +28
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Icon-only buttons need accessible names.

Icon-only controls on Lines 23-28 and Lines 45-46 should include aria-label so assistive tech can announce their purpose.

Also applies to: 45-46

🧰 Tools
🪛 Biome (2.4.4)

[error] 23-26: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorModal.tsx` around lines 23 - 28, Add
accessible names to the icon-only buttons by adding aria-label attributes:
update the close button (the <button onClick={onClose}> wrapping the <X /> icon
in ContributorModal.tsx) to include aria-label="Close" (or localized
equivalent), and also add a descriptive aria-label to the other icon-only
control referenced around lines 45-46 (the second icon-only <button> in this
component) that reflects its action (e.g., "Open profile" or "Copy email");
ensure the labels are concise, descriptive, and use aria-label on the button
elements so assistive tech can announce their purpose.

</div>
Comment on lines +16 to +29
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Modal lacks core dialog accessibility semantics.

The modal container is missing role="dialog", aria-modal, and an accessible title binding; this is a major accessibility gap for screen-reader and keyboard users.

♿ Proposed fix
-    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
-      <div className="bg-white dark:bg-gray-900 w-full max-w-2xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
+    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
+      <div
+        role="dialog"
+        aria-modal="true"
+        aria-labelledby="contributors-modal-title"
+        className="bg-white dark:bg-gray-900 w-full max-w-2xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200"
+      >
@@
-            <h2 className="text-xl font-bold dark:text-white">{title}</h2>
+            <h2 id="contributors-modal-title" className="text-xl font-bold dark:text-white">{title}</h2>
📝 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
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
<div className="bg-white dark:bg-gray-900 w-full max-w-2xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
<div className="p-6 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between">
<div>
<h2 className="text-xl font-bold dark:text-white">{title}</h2>
<p className="text-sm text-gray-500">{contributors.length} contributors found</p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
<div
role="dialog"
aria-modal="true"
aria-labelledby="contributors-modal-title"
className="bg-white dark:bg-gray-900 w-full max-w-2xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200"
>
<div className="p-6 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between">
<div>
<h2 id="contributors-modal-title" className="text-xl font-bold dark:text-white">{title}</h2>
<p className="text-sm text-gray-500">{contributors.length} contributors found</p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
🧰 Tools
🪛 Biome (2.4.4)

[error] 23-26: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorModal.tsx` around lines 16 - 29, Add
proper dialog accessibility to the modal wrapper in ContributorModal.tsx: give
the outer modal container div the attributes role="dialog" and
aria-modal="true", add an id to the title element (the <h2> rendering {title},
e.g., id="contributor-modal-title"), and set aria-labelledby on the dialog
container to that id so screen-readers announce the modal title; also ensure the
close button (onClose handler) has an accessible name (e.g., aria-label="Close")
so it is keyboard/screen-reader operable.


<div className="flex-1 overflow-y-auto p-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{contributors.map((c) => (
<div key={c.name} className="flex items-center justify-between p-4 rounded-xl border border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/50 flex items-center justify-center font-bold text-blue-600 dark:text-blue-400">
{c.name[0].toUpperCase()}
</div>
<div>
<p className="font-semibold text-sm dark:text-gray-200">{c.name}</p>
<p className="text-xs text-gray-500">{c.commits} commits</p>
</div>
</div>
<div className="flex space-x-1">
<button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><Mail className="w-4 h-4" /></button>
<button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><ExternalLink className="w-4 h-4" /></button>
Comment on lines +45 to +46
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These action buttons are non-functional in the current implementation.

The Mail and ExternalLink controls render as clickable buttons but have no onClick/href, so they do nothing when activated.

🧰 Tools
🪛 Biome (2.4.4)

[error] 45-45: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 46-46: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorModal.tsx` around lines 45 - 46, The Mail
and ExternalLink buttons in ContributorModal are rendered without actions;
update the JSX in ContributorModal.tsx to wire them to real handlers: for the
Mail (Mail icon) add an onClick or convert to an anchor using a mailto: link
built from the contributor's email (e.g., contributor.email) to open the user's
mail client, and for the ExternalLink add an onClick or anchor with
target="_blank" rel="noopener noreferrer" pointing to the contributor's external
URL (e.g., contributor.url or contributor.website); ensure you use the existing
contributor prop/state used in the component and keep accessibility (aria-label)
on the buttons/links.

</div>
</div>
))}
</div>
</div>

<div className="p-4 bg-gray-50 dark:bg-gray-800/50 border-t border-gray-100 dark:border-gray-800 text-center">
<button
onClick={onClose}
className="px-6 py-2 bg-gray-900 dark:bg-white dark:text-gray-900 text-white rounded-xl font-bold text-sm hover:opacity-90 transition-opacity"
>
Comment on lines +23 to +57
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add explicit button types to prevent implicit submit behavior.

Buttons at Lines 23, 45, 46, and 54 should declare type="button" explicitly.

🔧 Proposed fix
-          <button 
+          <button 
+            type="button"
             onClick={onClose}
             className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
           >
@@
-                   <button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><Mail className="w-4 h-4" /></button>
-                   <button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><ExternalLink className="w-4 h-4" /></button>
+                   <button type="button" className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><Mail className="w-4 h-4" /></button>
+                   <button type="button" className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><ExternalLink className="w-4 h-4" /></button>
@@
-          <button 
+          <button 
+            type="button"
             onClick={onClose}
             className="px-6 py-2 bg-gray-900 dark:bg-white dark:text-gray-900 text-white rounded-xl font-bold text-sm hover:opacity-90 transition-opacity"
           >
📝 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
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
<div className="flex-1 overflow-y-auto p-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{contributors.map((c) => (
<div key={c.name} className="flex items-center justify-between p-4 rounded-xl border border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/50 flex items-center justify-center font-bold text-blue-600 dark:text-blue-400">
{c.name[0].toUpperCase()}
</div>
<div>
<p className="font-semibold text-sm dark:text-gray-200">{c.name}</p>
<p className="text-xs text-gray-500">{c.commits} commits</p>
</div>
</div>
<div className="flex space-x-1">
<button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><Mail className="w-4 h-4" /></button>
<button className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><ExternalLink className="w-4 h-4" /></button>
</div>
</div>
))}
</div>
</div>
<div className="p-4 bg-gray-50 dark:bg-gray-800/50 border-t border-gray-100 dark:border-gray-800 text-center">
<button
onClick={onClose}
className="px-6 py-2 bg-gray-900 dark:bg-white dark:text-gray-900 text-white rounded-xl font-bold text-sm hover:opacity-90 transition-opacity"
>
<button
type="button"
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
<div className="flex-1 overflow-y-auto p-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{contributors.map((c) => (
<div key={c.name} className="flex items-center justify-between p-4 rounded-xl border border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/50 flex items-center justify-center font-bold text-blue-600 dark:text-blue-400">
{c.name[0].toUpperCase()}
</div>
<div>
<p className="font-semibold text-sm dark:text-gray-200">{c.name}</p>
<p className="text-xs text-gray-500">{c.commits} commits</p>
</div>
</div>
<div className="flex space-x-1">
<button type="button" className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><Mail className="w-4 h-4" /></button>
<button type="button" className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500"><ExternalLink className="w-4 h-4" /></button>
</div>
</div>
))}
</div>
</div>
<div className="p-4 bg-gray-50 dark:bg-gray-800/50 border-t border-gray-100 dark:border-gray-800 text-center">
<button
type="button"
onClick={onClose}
className="px-6 py-2 bg-gray-900 dark:bg-white dark:text-gray-900 text-white rounded-xl font-bold text-sm hover:opacity-90 transition-opacity"
>
🧰 Tools
🪛 Biome (2.4.4)

[error] 23-26: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 45-45: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 46-46: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 54-57: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Dashboard/ContributorModal.tsx` around lines 23 - 57, Four
button elements in ContributorModal (the close button with onClick={onClose},
the two icon buttons inside the contributors.map block, and the bottom action
button that also uses onClick={onClose}) are missing explicit types and may act
as implicit submit buttons; update each of those <button> elements to include
type="button" to prevent unintended form submission (locate them by the
onClick={onClose} button, the two icon buttons rendering <Mail> and
<ExternalLink>, and the bottom action button in the component).

Close
</button>
</div>
</div>
</div>
);
};
Loading