Skip to content
Merged
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
2 changes: 1 addition & 1 deletion FrontEnd/my-app/components/quest/DeadlineTimer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function DeadlineTimer({
return () => clearInterval(interval);
// Only re-run when the deadline string or the external isExpired flag changes,
// not on every tick — avoids interval thrash.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deadline, isExpired]);

if (isExpired || timeRemaining.isExpired) {
Expand Down
15 changes: 4 additions & 11 deletions FrontEnd/my-app/components/quest/QuestCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,10 @@ export const QuestCard = memo(
const cardLabel = `${quest.title}. Category: ${quest.category ?? 'Uncategorized'}, Difficulty: ${quest.difficulty}, Reward: ${rewardLabel}${timeInfo}`;

return (
<article
role="button"
tabIndex={0}
aria-label={cardLabel}
<button
type="button"
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick();
}
}}
aria-label={cardLabel}
className="quest-card"
>
<div className="quest-card__top" aria-hidden="true">
Expand Down Expand Up @@ -246,7 +239,7 @@ export const QuestCard = memo(
>
Quick Apply →
</button>
</article>
</button>
);
}
);
Expand Down
23 changes: 13 additions & 10 deletions FrontEnd/my-app/components/reputation/BadgeGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ function BadgeCard({
className="relative group"
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
onClick={onClick}
>
<div
className={`relative rounded-lg border-2 p-4 transition-all cursor-pointer ${
<button
type="button"
onClick={onClick}
aria-label={`View badge ${badge.name}`}
className={`relative rounded-lg border-2 p-4 transition-all text-left ${
isEarned
? `${rarityColors[badge.rarity]} bg-white dark:bg-zinc-900 hover:scale-105 hover:shadow-md`
: 'border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 opacity-50 grayscale'
Expand Down Expand Up @@ -99,7 +101,7 @@ function BadgeCard({
</div>
</div>
)}
</div>
</button>
</div>
);
}
Expand Down Expand Up @@ -145,12 +147,13 @@ export function BadgeGallery({
{badges.map((badge) => {
const isEarned = earnedBadgeIds.includes(badge.id);
return (
<BadgeCard
key={badge.id}
badge={badge}
isEarned={isEarned}
onClick={() => onBadgeClick?.(badge)}
/>
<div key={badge.id} className="relative group">
<BadgeCard
badge={badge}
isEarned={isEarned}
onClick={() => onBadgeClick?.(badge)}
/>
</div>
);
})}
</div>
Expand Down
15 changes: 4 additions & 11 deletions FrontEnd/my-app/components/submission/SubmissionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,11 @@ export const SubmissionCard = memo(function SubmissionCard({
const formattedDate = formatRelativeDate(submission.createdAt);

return (
<div
<button
onClick={handleClick}
className="group cursor-pointer rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-all hover:border-zinc-300 hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900 dark:hover:border-zinc-700"
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick();
}
}}
className="group cursor-pointer rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-all hover:border-zinc-300 hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900 dark:hover:border-zinc-700 text-left"
aria-label={`View submission for ${submission.quest.title}`}
type="button"
>
<div className="flex items-start justify-between gap-4">
<div className="flex-1 min-w-0">
Expand All @@ -54,7 +47,7 @@ export const SubmissionCard = memo(function SubmissionCard({
<StatusBadge status={submission.status} />
</div>
</div>
</div>
</button>
);
});

Expand Down
25 changes: 14 additions & 11 deletions FrontEnd/my-app/components/submission/SubmissionDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,26 @@ export function SubmissionDetail({

if (!isOpen || !submission) return null;

const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) {
onClose();
}
const handleBackdropClick = (e: React.MouseEvent<HTMLButtonElement>) => {
// backdrop button covers the container; close when clicked
onClose();
};

return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
onClick={handleBackdropClick}
role="dialog"
aria-modal="true"
aria-labelledby="submission-detail-title"
>
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<button
type="button"
className="absolute inset-0 bg-black/50 border-none p-0"
onClick={handleBackdropClick}
aria-label="Close submission details"
tabIndex={-1}
/>
<FocusTrap active={isOpen}>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby="submission-detail-title"
className="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-lg bg-white shadow-xl dark:bg-zinc-900"
tabIndex={-1}
>
Expand Down
60 changes: 48 additions & 12 deletions FrontEnd/my-app/components/submission/SubmissionsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,46 @@ export const SubmissionsTable = memo(function SubmissionsTable({
const hasProof = proofDisplay !== '-';

return (
<tr
key={submission.id}
onClick={() => onSubmissionClick?.(submission)}
className="cursor-pointer transition-colors hover:bg-zinc-50 dark:hover:bg-zinc-800"
>
<tr key={submission.id} className="transition-colors hover:bg-zinc-50 dark:hover:bg-zinc-800">
<td className="whitespace-nowrap px-6 py-4 text-sm font-medium text-zinc-900 dark:text-zinc-50">
{submission.id}
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="w-full text-left"
aria-label={`View submission ${submission.id}`}
>
{submission.id}
</button>
</td>
<td className="px-6 py-4 text-sm text-zinc-900 dark:text-zinc-50">
{submission.quest.title}
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="w-full text-left"
aria-label={`View submission for ${submission.quest.title}`}
>
{submission.quest.title}
</button>
</td>
<td className="whitespace-nowrap px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400">
{formatShortDate(submission.createdAt)}
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="w-full text-left"
aria-label={`View submission date ${submission.id}`}
>
{formatShortDate(submission.createdAt)}
</button>
</td>
<td className="whitespace-nowrap px-6 py-4 text-sm">
<StatusBadge status={submission.status} />
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="w-full text-left"
aria-label={`View submission status ${submission.id}`}
>
<StatusBadge status={submission.status} />
</button>
</td>
<td
className={`whitespace-nowrap px-6 py-4 text-sm font-medium ${
Expand All @@ -100,11 +124,23 @@ export const SubmissionsTable = memo(function SubmissionsTable({
: 'text-zinc-500 dark:text-zinc-400'
}`}
>
{submission.quest.rewardAmount} {submission.quest.rewardAsset}
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="w-full text-left"
aria-label={`View reward for submission ${submission.id}`}
>
{submission.quest.rewardAmount} {submission.quest.rewardAsset}
</button>
</td>
<td className="whitespace-nowrap px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400">
{hasProof ? (
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => onSubmissionClick?.(submission)}
className="flex w-full items-center gap-2 text-left"
aria-label={`View proof for submission ${submission.id}`}
>
<span>{proofDisplay}</span>
<svg
className="h-4 w-4"
Expand All @@ -119,7 +155,7 @@ export const SubmissionsTable = memo(function SubmissionsTable({
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
</div>
</button>
) : (
'-'
)}
Expand Down
16 changes: 5 additions & 11 deletions FrontEnd/my-app/components/ui/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ export function FileUpload({

return (
<div className="w-full">
<div
<button
type="button"
className={`relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed p-6 transition-colors ${
isDragging
? 'border-[#089ec3] bg-[#089ec3]/5'
Expand All @@ -206,20 +207,13 @@ export function FileUpload({
: selectedFile
? 'border-green-300 bg-green-50 dark:border-green-800 dark:bg-green-900/10'
: 'border-zinc-300 bg-zinc-50 hover:border-zinc-400 dark:border-zinc-700 dark:bg-zinc-800/50 dark:hover:border-zinc-600'
} ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}`}
} ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'} bg-transparent text-left`}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
onDrop={handleDrop}
onClick={handleClick}
role="button"
tabIndex={disabled ? -1 : 0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick();
}
}}
disabled={disabled}
aria-label="Upload file"
>
<input
Expand Down Expand Up @@ -303,7 +297,7 @@ export function FileUpload({
</p>
</>
)}
</div>
</button>

{displayError && (
<p className="mt-2 text-sm text-red-600 dark:text-red-400">
Expand Down
24 changes: 13 additions & 11 deletions FrontEnd/my-app/components/ui/LevelUpModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,8 @@ export function LevelUpModal({ isOpen, newLevel, onClose }: LevelUpModalProps) {

if (!isOpen) return null;

const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) {
onClose();
}
const handleBackdropClick = (e: React.MouseEvent<HTMLButtonElement>) => {
onClose();
};

return (
Expand All @@ -123,16 +121,20 @@ export function LevelUpModal({ isOpen, newLevel, onClose }: LevelUpModalProps) {
</div>

{/* Modal Overlay */}
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
onClick={handleBackdropClick}
role="dialog"
aria-modal="true"
aria-labelledby="level-up-title"
>
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<button
type="button"
className="absolute inset-0 bg-black/50 border-none p-0"
onClick={handleBackdropClick}
aria-label="Close level up modal"
tabIndex={-1}
/>
<FocusTrap active={isOpen}>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby="level-up-title"
className="relative w-full max-w-md rounded-lg bg-white shadow-xl dark:bg-zinc-900 animate-modal-entrance"
tabIndex={-1}
>
Expand Down
18 changes: 11 additions & 7 deletions FrontEnd/my-app/components/ui/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,20 @@ export function Modal({
if (!isOpen) return null;

return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
onClick={handleBackdropClick}
role="dialog"
aria-modal="true"
aria-labelledby={title ? 'modal-title' : undefined}
>
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<button
type="button"
className="absolute inset-0 bg-black/50 border-none p-0"
onClick={handleBackdropClick}
aria-label="Close modal"
tabIndex={-1}
/>
<FocusTrap active={isOpen} initialFocus={closeButtonRef as any}>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby={title ? 'modal-title' : undefined}
className={`relative w-full ${sizeClasses[size]} rounded-lg bg-white shadow-xl dark:bg-zinc-900 animate-modal-entrance`}
tabIndex={-1}
>
Expand Down
7 changes: 5 additions & 2 deletions FrontEnd/my-app/components/wallet/WalletConnectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
} else if (isConnected && isAuthenticated && isModalOpen) {
closeModal();
}
}, [isConnected, address, isAuthenticated, step, isConnecting, isModalOpen]);

Check warning on line 65 in FrontEnd/my-app/components/wallet/WalletConnectionModal.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint

React Hook useEffect has a missing dependency: 'closeModal'. Either include it or remove the dependency array

const handleGenerateChallenge = async (addr: string) => {
try {
Expand Down Expand Up @@ -108,12 +108,15 @@
<AnimatePresence>
{isModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center">
<motion.div
<motion.button
type="button"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
className="absolute inset-0 bg-black/60 backdrop-blur-sm border-none p-0"
onClick={closeModal}
aria-label="Close modal"
tabIndex={-1}
/>

<FocusTrap active={isModalOpen}>
Expand Down
10 changes: 5 additions & 5 deletions FrontEnd/my-app/components/wallet/WalletModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ export function WalletModal() {
return (
<AnimatePresence>
{isModalOpen && (
<div
className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm"
<button
type="button"
className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm border-none p-0"
onClick={closeModal}
role="button"
tabIndex={-1}
aria-label="Close wallet modal"
tabIndex={-1}
>
<FocusTrap active={isModalOpen}>
<motion.div
Expand Down Expand Up @@ -126,7 +126,7 @@ export function WalletModal() {
</div>
</motion.div>
</FocusTrap>
</div>
</button>
)}
</AnimatePresence>
);
Expand Down
Loading
Loading