Skip to content

Commit 004bb7b

Browse files
committed
Generated by Spark: the button does not do anything and dragging and dropping afile does nothin
1 parent 74bb7ce commit 004bb7b

3 files changed

Lines changed: 79 additions & 23 deletions

File tree

src/App.tsx

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useCallback } from "react";
1+
import { useState, useCallback, useRef, DragEvent } from "react";
22
import { Upload } from "@phosphor-icons/react";
33
import { toast } from "sonner";
44
import {
@@ -14,9 +14,10 @@ function App() {
1414
const [data, setData] = useState<CopilotUsageData[] | null>(null);
1515
const [aggregatedData, setAggregatedData] = useState<AggregatedData[]>([]);
1616
const [uniqueModels, setUniqueModels] = useState<string[]>([]);
17+
const [isDragging, setIsDragging] = useState(false);
18+
const fileInputRef = useRef<HTMLInputElement>(null);
1719

18-
const handleFileUpload = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
19-
const file = event.target.files?.[0];
20+
const processFile = useCallback((file: File) => {
2021
if (!file) return;
2122

2223
const reader = new FileReader();
@@ -48,6 +49,49 @@ function App() {
4849
reader.readAsText(file);
4950
}, []);
5051

52+
const handleFileUpload = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
53+
const file = event.target.files?.[0];
54+
if (file) {
55+
processFile(file);
56+
}
57+
// Reset the input value to allow selecting the same file again
58+
if (event.target) {
59+
event.target.value = '';
60+
}
61+
}, [processFile]);
62+
63+
const handleButtonClick = () => {
64+
fileInputRef.current?.click();
65+
};
66+
67+
const handleDragOver = useCallback((e: DragEvent<HTMLDivElement>) => {
68+
e.preventDefault();
69+
e.stopPropagation();
70+
setIsDragging(true);
71+
}, []);
72+
73+
const handleDragLeave = useCallback((e: DragEvent<HTMLDivElement>) => {
74+
e.preventDefault();
75+
e.stopPropagation();
76+
setIsDragging(false);
77+
}, []);
78+
79+
const handleDrop = useCallback((e: DragEvent<HTMLDivElement>) => {
80+
e.preventDefault();
81+
e.stopPropagation();
82+
setIsDragging(false);
83+
84+
const files = e.dataTransfer?.files;
85+
if (files && files.length > 0) {
86+
const file = files[0];
87+
if (file.type === "text/csv" || file.name.endsWith('.csv')) {
88+
processFile(file);
89+
} else {
90+
toast.error("Please upload a CSV file.");
91+
}
92+
}
93+
}, [processFile]);
94+
5195
// Generate chart data grouped by date with a stacked entry for each model
5296
const chartData = useCallback(() => {
5397
if (!aggregatedData.length) return [];
@@ -83,28 +127,34 @@ function App() {
83127
</header>
84128

85129
<Card className="mb-8">
86-
<div className="p-6 text-center">
130+
<div
131+
className={`p-6 text-center ${isDragging ? 'bg-secondary/50' : ''} transition-colors duration-200`}
132+
onDragOver={handleDragOver}
133+
onDragLeave={handleDragLeave}
134+
onDrop={handleDrop}
135+
>
87136
<div className="mb-4">
88137
<Upload size={48} weight="thin" className="mx-auto text-muted-foreground" />
89138
</div>
90139

91140
<h2 className="text-xl font-medium mb-2">Upload CSV File</h2>
92141
<p className="text-muted-foreground mb-4 max-w-md mx-auto">
93-
Upload your GitHub Copilot premium requests usage CSV export to visualize the data
142+
{isDragging
143+
? "Drop your file here..."
144+
: "Upload your GitHub Copilot premium requests usage CSV export to visualize the data. Drag and drop or select a file."}
94145
</p>
95146

96-
<label htmlFor="csv-upload">
97-
<Button as="div" className="cursor-pointer">
98-
Select CSV File
99-
</Button>
100-
<input
101-
id="csv-upload"
102-
type="file"
103-
accept=".csv"
104-
onChange={handleFileUpload}
105-
className="hidden"
106-
/>
107-
</label>
147+
<Button onClick={handleButtonClick} className="cursor-pointer">
148+
Select CSV File
149+
</Button>
150+
<input
151+
ref={fileInputRef}
152+
id="csv-upload"
153+
type="file"
154+
accept=".csv"
155+
onChange={handleFileUpload}
156+
className="hidden"
157+
/>
108158
</div>
109159
</Card>
110160

src/index.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,10 @@
7272

7373
body {
7474
font-family: 'Inter', sans-serif;
75+
}
76+
77+
/* Add styles for drag and drop */
78+
[data-dragging="true"] {
79+
border: 2px dashed var(--primary);
80+
background-color: var(--secondary);
7581
}

src/prd.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
## Essential Features
2222
1. **CSV Upload**
23-
- What: Allow users to upload GitHub Copilot usage CSV exports
24-
- Why: Provides the raw data needed for analysis
25-
- Success: Properly parses CSV format with correct data types and handles validation
23+
- What: Allow users to upload GitHub Copilot usage CSV exports via file selection or drag-and-drop interface
24+
- Why: Provides flexible options for adding data to the analysis
25+
- Success: Properly parses CSV format with correct data types and handles validation with clear feedback
2626

2727
2. **Stacked Line Graph**
2828
- What: Visualize request data by model per day with color-coded status indicators
@@ -79,9 +79,9 @@
7979
- **Contextual Appropriateness**: Minimal animations focused on data state changes
8080

8181
### UI Elements & Component Selection
82-
- **Component Usage**: Card for the upload area, Button for triggering upload, Toast for notifications
83-
- **Component Customization**: Rounded corners and subtle shadows for cards
84-
- **Component States**: Clear hover/focus states for interactive elements
82+
- **Component Usage**: Card with drag-and-drop support for the upload area, Button for triggering upload, Toast for notifications
83+
- **Component Customization**: Rounded corners and subtle shadows for cards, visual feedback for drag states
84+
- **Component States**: Clear hover/focus states for interactive elements, distinctive styling for drag-over states
8585
- **Icon Selection**: Upload icon, chart icon, and information icon where appropriate
8686
- **Component Hierarchy**: Upload component as primary action initially, chart as main focus after data load
8787
- **Spacing System**: Consistent spacing using Tailwind's spacing scale

0 commit comments

Comments
 (0)