-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from DemocracyDevelopers/feature/link-frontend
Feature/link frontend
- Loading branch information
Showing
5 changed files
with
291 additions
and
18 deletions.
There are no files selected for viewing
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,125 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import { AlertCircle, X, CloudUpload } from "lucide-react"; | ||
|
||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; | ||
|
||
interface UploaderProps { | ||
className?: string; // Optional className prop | ||
} | ||
|
||
const Uploader: React.FC<UploaderProps> = ({ className }) => { | ||
const [selectedFile, setSelectedFile] = useState<File | null>(null); | ||
const [showAlert, setShowAlert] = useState(false); | ||
const allowedFileTypes = [".json", ".txt"]; // Allowed file extensions | ||
const maxFileSize = 100 * 1024 * 1024; // 100MB | ||
|
||
useEffect(() => { | ||
let timer: NodeJS.Timeout; | ||
if (showAlert) { | ||
timer = setTimeout(() => { | ||
setShowAlert(false); | ||
}, 2000); | ||
} | ||
return () => clearTimeout(timer); | ||
}, [showAlert]); | ||
|
||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
const file = event.target.files?.[0]; | ||
if (file && allowedFileTypes.includes(file.name.split(".").pop() || "")) { | ||
setSelectedFile(file); | ||
setShowAlert(false); | ||
} else { | ||
setShowAlert(true); | ||
} | ||
}; | ||
|
||
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => { | ||
event.preventDefault(); | ||
}; | ||
|
||
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => { | ||
event.preventDefault(); | ||
const file = event.dataTransfer.files?.[0]; | ||
if ( | ||
file && | ||
allowedFileTypes.includes(file.name.split(".").pop() || "") && | ||
file.size <= maxFileSize | ||
) { | ||
setSelectedFile(file); | ||
setShowAlert(false); | ||
} else { | ||
setShowAlert(true); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className={className}> | ||
{showAlert && ( | ||
<div className="fixed top-2 right-2 z-50"> | ||
<Alert | ||
variant="destructive" | ||
className="flex justify-between items-center" | ||
> | ||
<div className="flex items-center"> | ||
<AlertCircle className="h-4 w-4 mr-2" /> | ||
<div> | ||
<AlertTitle>Error</AlertTitle> | ||
<AlertDescription> | ||
Invalid file type or file size exceeds the limit. | ||
</AlertDescription> | ||
</div> | ||
</div> | ||
<button | ||
onClick={() => setShowAlert(false)} | ||
className="ml-4 transition transform hover:scale-110 active:scale-90" | ||
> | ||
<X className="h-4 w-4" /> | ||
</button> | ||
</Alert> | ||
</div> | ||
)} | ||
|
||
<h2 className="text-2xl font-bold">Upload your data</h2> | ||
<p className="mb-4 text-sm text-gray-500"> | ||
Use the dropzone below to upload your file. | ||
</p> | ||
|
||
<div | ||
className="border-2 border-gray-300 p-8 rounded-lg bg-gray-50 cursor-pointer w-full relative text-center flex flex-grow justify-center items-center " | ||
onDragOver={handleDragOver} | ||
onDrop={handleDrop} | ||
> | ||
<div className=""> | ||
<CloudUpload className="mx-auto mb-2" size={80} /> | ||
<p className="text-gray-600"> | ||
Drag or <span className="text-blue-600 cursor-pointer">Browse</span>{" "} | ||
your files | ||
</p> | ||
<p className="text-gray-400 mb-2">or</p> | ||
<a href="#" className="text-blue-600"> | ||
Use a sample file | ||
</a> | ||
|
||
<input | ||
type="file" | ||
accept=".json, .txt" | ||
onChange={handleFileChange} | ||
className="top-0 left-0 w-full h-full opacity-0 cursor-pointer" | ||
/> | ||
<p className="text-sm text-gray-400 mt-4 absolute bottom-2 left-2"> | ||
Supported files: .json, .txt | Upload limit: 100MB | ||
</p> | ||
</div> | ||
</div> | ||
|
||
{selectedFile && ( | ||
<div className="mt-4"> | ||
<p>Selected file: {selectedFile.name}</p> | ||
<p>File type: {selectedFile.type}</p> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Uploader; |
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,59 @@ | ||
import * as React from "react"; | ||
import { cva, type VariantProps } from "class-variance-authority"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const alertVariants = cva( | ||
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", | ||
{ | ||
variants: { | ||
variant: { | ||
default: "bg-background text-foreground", | ||
destructive: | ||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: "default", | ||
}, | ||
}, | ||
); | ||
|
||
const Alert = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants> | ||
>(({ className, variant, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
role="alert" | ||
className={cn(alertVariants({ variant }), className)} | ||
{...props} | ||
/> | ||
)); | ||
Alert.displayName = "Alert"; | ||
|
||
const AlertTitle = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLHeadingElement> | ||
>(({ className, ...props }, ref) => ( | ||
<h5 | ||
ref={ref} | ||
className={cn("mb-1 font-medium leading-none tracking-tight", className)} | ||
{...props} | ||
/> | ||
)); | ||
AlertTitle.displayName = "AlertTitle"; | ||
|
||
const AlertDescription = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLParagraphElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn("text-sm [&_p]:leading-relaxed", className)} | ||
{...props} | ||
/> | ||
)); | ||
AlertDescription.displayName = "AlertDescription"; | ||
|
||
export { Alert, AlertTitle, AlertDescription }; |
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,50 @@ | ||
"use client"; | ||
|
||
import * as React from "react"; | ||
import * as AvatarPrimitive from "@radix-ui/react-avatar"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const Avatar = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Root | ||
ref={ref} | ||
className={cn( | ||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
Avatar.displayName = AvatarPrimitive.Root.displayName; | ||
|
||
const AvatarImage = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Image>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Image | ||
ref={ref} | ||
className={cn("aspect-square h-full w-full", className)} | ||
{...props} | ||
/> | ||
)); | ||
AvatarImage.displayName = AvatarPrimitive.Image.displayName; | ||
|
||
const AvatarFallback = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Fallback>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Fallback | ||
ref={ref} | ||
className={cn( | ||
"flex h-full w-full items-center justify-center rounded-full bg-muted", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; | ||
|
||
export { Avatar, AvatarImage, AvatarFallback }; |
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 @@ | ||
"use client"; | ||
|
||
import * as React from "react"; | ||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const TooltipProvider = TooltipPrimitive.Provider; | ||
|
||
const Tooltip = TooltipPrimitive.Root; | ||
|
||
const TooltipTrigger = TooltipPrimitive.Trigger; | ||
|
||
const TooltipContent = React.forwardRef< | ||
React.ElementRef<typeof TooltipPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> | ||
>(({ className, sideOffset = 4, ...props }, ref) => ( | ||
<TooltipPrimitive.Content | ||
ref={ref} | ||
sideOffset={sideOffset} | ||
className={cn( | ||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
TooltipContent.displayName = TooltipPrimitive.Content.displayName; | ||
|
||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; |