Skip to content

Commit

Permalink
Merge pull request #45 from DemocracyDevelopers/feature/link-frontend
Browse files Browse the repository at this point in the history
Feature/link frontend
  • Loading branch information
Mirrorgo authored Sep 27, 2024
2 parents babc74b + 9c3a8db commit 992e8c3
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 18 deletions.
125 changes: 125 additions & 0 deletions app/dashboard/components/uploader.tsx
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;
45 changes: 27 additions & 18 deletions app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use client";

import Image from "next/image";
import Uploader from "./components/uploader";
import React, { useEffect } from "react";

const Dashboard: React.FC = () => {
Expand All @@ -17,24 +19,31 @@ const Dashboard: React.FC = () => {
}, []);

return (
<div className="flex h-screen">
{/* Left Tool Bar */}
<aside className="w-1/8 bg-gray-800 text-white p-6">
<h2 className="text-xl font-semibold mb-6">AuditVisualizer</h2>
<ul className="space-y-4">
<li className="hover:bg-gray-700 p-2 rounded">Main</li>
<li className="hover:bg-gray-700 p-2 rounded">Func_1</li>
<li className="hover:bg-gray-700 p-2 rounded">Func_2</li>
<li className="hover:bg-gray-700 p-2 rounded">Setting</li>
</ul>
</aside>

{/* Main Work Space */}
<main className="flex-1 bg-gray-100 p-8">
<h1 className="text-3xl font-bold mb-6">Dashboard</h1>
<div className="bg-white shadow-md rounded-lg p-6">
<p>TODO</p>
{/* Add more Stuff here*/}
<div className="flex flex-col h-screen">
<main className="flex flex-col bg-gray-100 p-8 h-screen">
<div className="flex items-center mb-6">
<Image src="/Logo.png" alt="Logo" width={80} height={80} />
<h1 className="text-3xl font-bold">AuditVisualiser</h1>
</div>
<div className="bg-white shadow-md rounded-lg p-6 flex flex-col flex-grow">
<h2 className="text-3xl font-bold text-left">
Show the effect of assertions
</h2>
<p className="text-gray-500 text-left">
Evaluate any audit result that is formatted as a JSON file.
</p>
<Uploader className="flex flex-col flex-grow text-left p-4" />
<p className="bg-white text-gray-400 text-center">
By sharing your files or using our service, you agree to our&nbsp;
<span className="underline hover:text-gray-800">
Terms of Service
</span>
&nbsp;and&nbsp;
<span className="underline hover:text-gray-800">
Privacy Policy
</span>
.
</p>
</div>
</main>
</div>
Expand Down
59 changes: 59 additions & 0 deletions components/ui/alert.tsx
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 };
50 changes: 50 additions & 0 deletions components/ui/avatar.tsx
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 };
30 changes: 30 additions & 0 deletions components/ui/tooltip.tsx
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 };

0 comments on commit 992e8c3

Please sign in to comment.