Skip to content

Commit 37a2702

Browse files
Copilotankurrera
andcommitted
Address code review feedback: use design system colors, constants, and custom dialogs
Co-authored-by: ankurrera <186232326+ankurrera@users.noreply.github.com>
1 parent 71ca53c commit 37a2702

6 files changed

Lines changed: 142 additions & 14 deletions

File tree

src/components/skills/CharacteristicCard.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button } from "@/components/ui/button";
44
import { Input } from "@/components/ui/input";
55
import { calculateLevelProgress } from "@/lib/levelCalculation";
66
import { Edit2, Trash2, Save, X, Star } from "lucide-react";
7+
import ConfirmDialog from "./ConfirmDialog";
78

89
interface CharacteristicCardProps {
910
characteristic: Characteristic;
@@ -12,6 +13,7 @@ interface CharacteristicCardProps {
1213
const CharacteristicCard = ({ characteristic }: CharacteristicCardProps) => {
1314
const { updateCharacteristic, deleteCharacteristic } = useCharacteristics();
1415
const [isEditing, setIsEditing] = useState(false);
16+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
1517
const [editName, setEditName] = useState(characteristic.name);
1618
const [editIcon, setEditIcon] = useState(characteristic.icon);
1719
const [editXP, setEditXP] = useState(characteristic.xp.toString());
@@ -36,13 +38,17 @@ const CharacteristicCard = ({ characteristic }: CharacteristicCardProps) => {
3638
};
3739

3840
const handleDelete = () => {
39-
if (window.confirm(`Delete characteristic "${characteristic.name}"?`)) {
40-
deleteCharacteristic.mutate(characteristic.id);
41-
}
41+
setShowDeleteDialog(true);
42+
};
43+
44+
const confirmDelete = () => {
45+
deleteCharacteristic.mutate(characteristic.id);
46+
setShowDeleteDialog(false);
4247
};
4348

4449
return (
45-
<div className="system-panel p-4 space-y-3">
50+
<>
51+
<div className="system-panel p-4 space-y-3">
4652
{/* Header */}
4753
<div className="flex items-start justify-between">
4854
<div className="flex items-center gap-3 flex-1">
@@ -86,7 +92,7 @@ const CharacteristicCard = ({ characteristic }: CharacteristicCardProps) => {
8692
<Button
8793
variant="ghost"
8894
size="icon"
89-
className="h-8 w-8 text-green-600 hover:text-green-700 hover:bg-green-50"
95+
className="h-8 w-8 text-primary hover:text-primary/80 hover:bg-primary/10"
9096
onClick={handleSave}
9197
>
9298
<Save className="w-4 h-4" />
@@ -153,6 +159,16 @@ const CharacteristicCard = ({ characteristic }: CharacteristicCardProps) => {
153159
</div>
154160
</div>
155161
</div>
162+
163+
{/* Delete Confirmation Dialog */}
164+
<ConfirmDialog
165+
open={showDeleteDialog}
166+
onOpenChange={setShowDeleteDialog}
167+
title="Delete Characteristic"
168+
description={`Are you sure you want to delete "${characteristic.name}"? This action cannot be undone.`}
169+
onConfirm={confirmDelete}
170+
/>
171+
</>
156172
);
157173
};
158174

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {
2+
AlertDialog,
3+
AlertDialogAction,
4+
AlertDialogCancel,
5+
AlertDialogContent,
6+
AlertDialogDescription,
7+
AlertDialogFooter,
8+
AlertDialogHeader,
9+
AlertDialogTitle,
10+
} from "@/components/ui/alert-dialog";
11+
12+
interface ConfirmDialogProps {
13+
open: boolean;
14+
onOpenChange: (open: boolean) => void;
15+
title: string;
16+
description: string;
17+
onConfirm: () => void;
18+
confirmText?: string;
19+
cancelText?: string;
20+
}
21+
22+
const ConfirmDialog = ({
23+
open,
24+
onOpenChange,
25+
title,
26+
description,
27+
onConfirm,
28+
confirmText = "Delete",
29+
cancelText = "Cancel",
30+
}: ConfirmDialogProps) => {
31+
return (
32+
<AlertDialog open={open} onOpenChange={onOpenChange}>
33+
<AlertDialogContent className="system-panel">
34+
<AlertDialogHeader>
35+
<AlertDialogTitle className="text-foreground">
36+
{title}
37+
</AlertDialogTitle>
38+
<AlertDialogDescription className="text-muted-foreground">
39+
{description}
40+
</AlertDialogDescription>
41+
</AlertDialogHeader>
42+
<AlertDialogFooter>
43+
<AlertDialogCancel className="border-border hover:bg-muted">
44+
{cancelText}
45+
</AlertDialogCancel>
46+
<AlertDialogAction
47+
onClick={onConfirm}
48+
className="bg-destructive hover:bg-destructive/90 text-destructive-foreground"
49+
>
50+
{confirmText}
51+
</AlertDialogAction>
52+
</AlertDialogFooter>
53+
</AlertDialogContent>
54+
</AlertDialog>
55+
);
56+
};
57+
58+
export default ConfirmDialog;

src/components/skills/CreateCharacteristicForm.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ import { useCharacteristics } from "@/hooks/useCharacteristics";
33
import { Button } from "@/components/ui/button";
44
import { Input } from "@/components/ui/input";
55
import { X } from "lucide-react";
6+
import { CHARACTERISTIC_ICONS } from "@/lib/skillsConstants";
67

78
interface CreateCharacteristicFormProps {
89
onClose: () => void;
910
}
1011

11-
const iconOptions = ["⭐", "💪", "🧠", "❤️", "⚡", "🎯", "🛡️", "⚔️", "🏃", "🎨"];
12-
1312
const CreateCharacteristicForm = ({ onClose }: CreateCharacteristicFormProps) => {
1413
const { createCharacteristic } = useCharacteristics();
1514
const [name, setName] = useState("");
16-
const [icon, setIcon] = useState("⭐");
15+
const [icon, setIcon] = useState(CHARACTERISTIC_ICONS[0]);
1716
const [xp, setXP] = useState("0");
1817

1918
const handleSubmit = (e: React.FormEvent) => {
@@ -57,7 +56,7 @@ const CreateCharacteristicForm = ({ onClose }: CreateCharacteristicFormProps) =>
5756
Icon
5857
</label>
5958
<div className="grid grid-cols-5 gap-2">
60-
{iconOptions.map((iconOption) => (
59+
{CHARACTERISTIC_ICONS.map((iconOption) => (
6160
<button
6261
key={iconOption}
6362
type="button"

src/components/skills/SkillCard.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button } from "@/components/ui/button";
44
import { calculateLevelProgress } from "@/lib/levelCalculation";
55
import { Edit2, Trash2, Star, Power, PowerOff } from "lucide-react";
66
import EditSkillDialog from "./EditSkillDialog";
7+
import ConfirmDialog from "./ConfirmDialog";
78

89
interface SkillCardProps {
910
skill: Skill;
@@ -12,6 +13,7 @@ interface SkillCardProps {
1213
const SkillCard = ({ skill }: SkillCardProps) => {
1314
const { updateSkill, deleteSkill } = useSkills();
1415
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
16+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
1517

1618
const progress = calculateLevelProgress(skill.xp);
1719

@@ -23,9 +25,12 @@ const SkillCard = ({ skill }: SkillCardProps) => {
2325
};
2426

2527
const handleDelete = () => {
26-
if (window.confirm(`Delete skill "${skill.name}"?`)) {
27-
deleteSkill.mutate(skill.id);
28-
}
28+
setShowDeleteDialog(true);
29+
};
30+
31+
const confirmDelete = () => {
32+
deleteSkill.mutate(skill.id);
33+
setShowDeleteDialog(false);
2934
};
3035

3136
return (
@@ -135,7 +140,7 @@ const SkillCard = ({ skill }: SkillCardProps) => {
135140
onClick={handleToggleActive}
136141
className={`h-7 px-3 text-xs ${
137142
skill.is_active
138-
? "text-green-600 hover:text-green-700"
143+
? "text-primary hover:text-primary/80"
139144
: "text-muted-foreground hover:text-foreground"
140145
}`}
141146
>
@@ -156,6 +161,15 @@ const SkillCard = ({ skill }: SkillCardProps) => {
156161
open={isEditDialogOpen}
157162
onOpenChange={setIsEditDialogOpen}
158163
/>
164+
165+
{/* Delete Confirmation Dialog */}
166+
<ConfirmDialog
167+
open={showDeleteDialog}
168+
onOpenChange={setShowDeleteDialog}
169+
title="Delete Skill"
170+
description={`Are you sure you want to delete "${skill.name}"? This action cannot be undone.`}
171+
onConfirm={confirmDelete}
172+
/>
159173
</>
160174
);
161175
};

src/lib/skillsConstants.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Constants for the Skills system
3+
*/
4+
5+
export const CHARACTERISTIC_ICONS = [
6+
"⭐", "💪", "🧠", "❤️", "⚡",
7+
"🎯", "🛡️", "⚔️", "🏃", "🎨"
8+
] as const;
9+
10+
export const SKILL_AREAS = [
11+
"Programming",
12+
"Music",
13+
"Fitness",
14+
"Art",
15+
"Languages",
16+
"Business",
17+
"Science",
18+
"Writing",
19+
] as const;
20+
21+
/**
22+
* Level progression formula constants
23+
* Level = floor(sqrt(XP / 100)) + 1
24+
*
25+
* XP Thresholds:
26+
* Level 1: 0-99 XP
27+
* Level 2: 100-399 XP
28+
* Level 3: 400-899 XP
29+
* Level 4: 900-1599 XP
30+
* Level 5: 1600-2499 XP
31+
* Level 10: 8100-9999 XP
32+
* Level 20: 36100-40099 XP
33+
*/
34+
export const XP_LEVEL_MULTIPLIER = 100;

supabase/migrations/20260127000000_add_skills_system.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,14 @@ IMMUTABLE
9090
AS $$
9191
BEGIN
9292
-- Level calculation: Level = floor(sqrt(XP / 100)) + 1
93-
-- This means: Level 1 = 0-99 XP, Level 2 = 100-399 XP, Level 3 = 400-899 XP, etc.
93+
-- XP Thresholds:
94+
-- Level 1: 0-99 XP
95+
-- Level 2: 100-399 XP
96+
-- Level 3: 400-899 XP
97+
-- Level 4: 900-1599 XP
98+
-- Level 5: 1600-2499 XP
99+
-- Level 10: 8100-9999 XP
100+
-- Level 20: 36100-40099 XP
94101
RETURN FLOOR(SQRT(xp_amount / 100.0)) + 1;
95102
END;
96103
$$;

0 commit comments

Comments
 (0)