-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement csv upload functionality and refactor index page
- Loading branch information
Showing
9 changed files
with
294 additions
and
101 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Info } from "lucide-react" | ||
import { Button } from "@/components/ui/button" | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogDescription, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog" | ||
|
||
export function CSVInformationDialog() { | ||
return ( | ||
<Dialog> | ||
<DialogTrigger asChild> | ||
<Button variant="outline" size="icon" className="min-w-10"> | ||
<Info className="text-primary" strokeWidth={2.5} /> | ||
</Button> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Instructions for preparing CSV</DialogTitle> | ||
<DialogDescription> | ||
yeah mate | ||
</DialogDescription> | ||
</DialogHeader> | ||
</DialogContent> | ||
</Dialog> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { cn } from "@/lib/utils" | ||
import { TriangleAlert } from "lucide-react" | ||
|
||
export function CSVUploadAlert({ className }: { className?: string }) { | ||
return ( | ||
<div className={cn("flex items-center gap-2 p-2 border rounded-md text-sm border-[#fdf5d3] dark:border-[#3d3d00] text-[#dc7609] dark:text-[#f3cf58] [&>svg]:text-[#dc7609] [&>svg]:dark:text-[#f3cf58]", className)}> | ||
<TriangleAlert className="h-4 w-4 !top-auto" /> | ||
Uploading CSV will replace all current data. | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Upload } from "lucide-react" | ||
import { CSVUploadAlert } from "@/components/csv/csv-upload-alert" | ||
import { CSVUploader } from "@/components/csv/csv-uploader" | ||
import { Button } from "@/components/ui/button" | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogDescription, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog" | ||
|
||
export function CSVUploadDialog() { | ||
return ( | ||
<Dialog> | ||
<DialogTrigger asChild> | ||
<Button variant="outline"> | ||
<Upload className="" strokeWidth={2.5} /> | ||
<span className="sm:hidden">CSV</span> | ||
<span className="hidden sm:inline">Upload CSV</span> | ||
</Button> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Upload CSV</DialogTitle> | ||
</DialogHeader> | ||
<CSVUploadAlert /> | ||
<DialogDescription className="hidden"> | ||
Upload a CSV file to replace all current data | ||
</DialogDescription> | ||
<CSVUploader | ||
onCSVUpload={(csvData) => { | ||
// Here you can process the CSV data | ||
console.log(csvData) | ||
}} | ||
/> | ||
</DialogContent> | ||
</Dialog> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import * as React from "react" | ||
import { FileText, Upload, X } from "lucide-react" | ||
import Dropzone, { DropzoneRootProps, DropzoneInputProps } from "react-dropzone" | ||
import { toast } from "sonner" | ||
import { cn } from "@/lib/utils" | ||
import { Button } from "@/components/ui/button" | ||
|
||
interface CSVUploaderProps extends React.HTMLAttributes<HTMLDivElement> { | ||
onCSVUpload: (data: string) => void | ||
disabled?: boolean | ||
className?: string | ||
} | ||
|
||
export function CSVUploader({ onCSVUpload, disabled = false, className }: CSVUploaderProps) { | ||
const [file, setFile] = React.useState<File | null>(null) | ||
|
||
const onDrop = React.useCallback( | ||
(acceptedFiles: File[]) => { | ||
if (acceptedFiles.length === 0) { | ||
toast.error("Please upload a CSV file") | ||
return | ||
} | ||
|
||
const csvFile = acceptedFiles[0] | ||
setFile(csvFile) | ||
|
||
// Read and process the CSV file | ||
const reader = new FileReader() | ||
reader.onload = (event) => { | ||
if (event.target?.result) { | ||
const csvData = event.target.result as string | ||
onCSVUpload(csvData) | ||
} | ||
} | ||
reader.readAsText(csvFile) | ||
}, | ||
[onCSVUpload] | ||
) | ||
|
||
function onRemove() { | ||
setFile(null) | ||
} | ||
|
||
return ( | ||
<div className="relative flex flex-col gap-4"> | ||
<Dropzone | ||
onDrop={onDrop} | ||
accept={{ "text/csv": [".csv"] }} | ||
maxFiles={1} | ||
multiple={false} | ||
disabled={disabled} | ||
> | ||
{({ getRootProps, getInputProps, isDragActive }: { | ||
getRootProps: () => DropzoneRootProps; | ||
getInputProps: () => DropzoneInputProps; | ||
isDragActive: boolean; | ||
}) => ( | ||
<div | ||
{...getRootProps()} | ||
className={cn( | ||
"group relative grid h-40 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed border-muted-foreground/25 px-5 py-2.5 text-center transition hover:bg-muted/25", | ||
isDragActive && "border-muted-foreground/50", | ||
disabled && "pointer-events-none opacity-60", | ||
className | ||
)} | ||
> | ||
<input {...getInputProps()} /> | ||
<div className="flex flex-col items-center justify-center gap-4"> | ||
<Upload | ||
className="h-8 w-8 text-muted-foreground" | ||
aria-hidden="true" | ||
/> | ||
<div className="flex flex-col gap-1"> | ||
<p className="hidden sm:inline font-medium text-muted-foreground"> | ||
{isDragActive | ||
? "Drop the CSV file here" | ||
: "Drag and drop a CSV file, or click to select"} | ||
</p> | ||
<p className="sm:hidden font-medium text-muted-foreground"> | ||
Click to select a CSV file | ||
</p> | ||
{/* <p className="text-sm text-muted-foreground/70"> | ||
You can only upload one file | ||
</p> */} | ||
</div> | ||
</div> | ||
</div> | ||
)} | ||
</Dropzone> | ||
|
||
{file && ( | ||
<div className="flex items-center gap-2 rounded-lg border p-2"> | ||
<FileText className="h-6 w-6 text-muted-foreground" /> | ||
<div className="flex flex-1 flex-col"> | ||
<p className="text-sm font-medium">{file.name}</p> | ||
<p className="text-xs text-muted-foreground"> | ||
{(file.size / 1024).toFixed(2)} KB | ||
</p> | ||
</div> | ||
<Button | ||
type="button" | ||
variant="ghost" | ||
size="icon" | ||
className="h-8 w-8" | ||
onClick={onRemove} | ||
> | ||
<X className="h-4 w-4" /> | ||
<span className="sr-only">Remove file</span> | ||
</Button> | ||
</div> | ||
)} | ||
</div> | ||
) | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { useBreakpoint } from '@/hooks/use-breakpoint' | ||
import { calculateColor } from "@/lib/calculate" | ||
import { RadialChart } from "@/components/radial-chart" | ||
import { useTheme } from "@/components/theme/theme-provider" | ||
|
||
import { | ||
Card, | ||
CardContent, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card" | ||
|
||
type StatCardProps = { | ||
title: string | ||
subtitle: string | ||
value: number | ||
maxValue: number | ||
} | ||
|
||
export function StatCard({ title, subtitle, value, maxValue }: StatCardProps) { | ||
const { theme } = useTheme() | ||
const isDarkMode = theme === "dark" | ||
const color = calculateColor(value, maxValue, isDarkMode) | ||
const { isMobile } = useBreakpoint() | ||
|
||
return ( | ||
<Card> | ||
<CardHeader> | ||
<CardTitle className="md:text-center"> | ||
{title} <span className="hidden md:inline text-xl text-muted-foreground">({subtitle})</span> | ||
</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
{!isMobile && ( | ||
<RadialChart | ||
className="font-mono" | ||
value={value} | ||
maxValue={maxValue} | ||
color={color} | ||
/> | ||
)} | ||
{isMobile && ( | ||
<p | ||
className="text-3xl sm:text-4xl font-bold font-mono" | ||
style={{ color: color }} | ||
> | ||
{value} | ||
</p> | ||
)} | ||
</CardContent> | ||
</Card> | ||
) | ||
} |
Oops, something went wrong.