Merge branch 'main' of github.com:nimbusdotstorage/Nimbus into license

This commit is contained in:
Logan Reeder
2025-06-16 14:48:23 -06:00
18 changed files with 106 additions and 105 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

After

Width:  |  Height:  |  Size: 500 KiB

View File

@@ -1,19 +1,12 @@
"use client";
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
import type { ComponentProps, ReactNode } from "react";
import { ArrowLeft, ArrowRight } from "lucide-react";
import type { AuthCardProps } from "@/lib/types";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import Link from "next/link";
interface AuthCardProps extends ComponentProps<"div"> {
title: string;
description: string;
navigationType: "signin" | "signup";
children: ReactNode;
}
export function AuthCard({ title, description, navigationType, children, className, ...props }: AuthCardProps) {
const oppositeAction = navigationType === "signin" ? "signup" : "signin";
const oppositeActionText = navigationType === "signin" ? "Sign up" : "Sign in";

View File

@@ -1,15 +1,10 @@
"use client";
import { useState, type ChangeEvent } from "react";
import type { PasswordInputProps } from "@/lib/types";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Eye, EyeClosed } from "lucide-react";
import type { ComponentProps } from "react";
interface PasswordInputProps extends Omit<ComponentProps<typeof Input>, "type"> {
value?: string;
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}
import { useState } from "react";
export function PasswordInput({ className, ...props }: PasswordInputProps) {
const [isVisible, setIsVisible] = useState(false);

View File

@@ -1,16 +1,8 @@
"use client";
import type { SocialAuthButtonProps } from "@/lib/types";
import { Google } from "@/components/icons/google";
import { Button } from "@/components/ui/button";
import type { ComponentProps } from "react";
type SocialProvider = "google";
type AuthAction = "signin" | "signup";
interface SocialAuthButtonProps extends Omit<ComponentProps<typeof Button>, "children" | "variant" | "type"> {
provider: SocialProvider;
action: AuthAction;
}
const providerConfig = {
google: {

View File

@@ -6,6 +6,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import type { CreateFolderDialogProps } from "@/lib/types";
import { useState, type FormEvent } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
@@ -13,12 +14,6 @@ import { Input } from "@/components/ui/input";
import { toast } from "sonner";
import type React from "react";
interface CreateFolderDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onCreateFolder: (folderName: string, parentId?: string | undefined) => void;
}
export function CreateFolderDialog({ open, onOpenChange, onCreateFolder }: CreateFolderDialogProps) {
const [folderName, setFolderName] = useState("");

View File

@@ -8,16 +8,11 @@ import {
} from "@/components/ui/dialog";
import { UploadZone } from "@/components/upload/upload-zone";
import { useState, useEffect, type FormEvent } from "react";
import type { UploadFileDialogProps } from "@/lib/types";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import type React from "react";
interface UploadFileDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onUpload: (files: FileList) => void;
}
export function UploadFileDialog({ open, onOpenChange, onUpload }: UploadFileDialogProps) {
const [selectedFiles, setSelectedFiles] = useState<FileList | null>(null);
const [isUploading, setIsUploading] = useState(false);

View File

@@ -8,16 +8,11 @@ import {
} from "@/components/ui/dialog";
import { UploadZone } from "@/components/upload/upload-zone";
import { useEffect, useState, type FormEvent } from "react";
import { type UploadFileDialogProps } from "@/lib/types";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
interface UploadFolderDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onUpload: (files: FileList) => void;
}
export function UploadFolderDialog({ open, onOpenChange, onUpload }: UploadFolderDialogProps) {
export function UploadFolderDialog({ open, onOpenChange, onUpload }: UploadFileDialogProps) {
const [selectedFolder, setSelectedFolder] = useState<FileList | null>(null);
const [isUploading, setIsUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);

View File

@@ -1,18 +1,14 @@
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet";
import { FileText, Folder, Image, Video, X } from "lucide-react";
import type { FileItem, FolderContentItem } from "@/lib/types";
import { useRouter, useSearchParams } from "next/navigation";
import { createRequest } from "@/hooks/createRequest";
import { Button } from "@/components/ui/button";
import { useRequest } from "@/hooks/useRequest";
import { Loader } from "@/components/loader";
import type { FileItem } from "@/lib/types";
import { parseError } from "@/utils/error";
import { useEffect } from "react";
interface FolderContentItem extends FileItem {
path?: string;
}
export function FilePreview() {
const router = useRouter();
const searchParams = useSearchParams();

View File

@@ -6,7 +6,6 @@ import { Sidebar, SidebarContent, SidebarHeader, SidebarRail } from "@/component
import SidebarFolders from "@/components/main-sidebar/sidebar-folders";
import StorageFooter from "@/components/main-sidebar/sidebar-footer";
import { QuickAccess } from "@/components/main-sidebar/quick-access";
import type { Source } from "@/components/main-sidebar/sources";
import UploadButton from "@/components/main-sidebar/upload";
import TagMenu from "@/components/main-sidebar/tag-menu";
import Sources from "@/components/main-sidebar/sources";
@@ -14,6 +13,7 @@ import { HardDrive, Users, Server } from "lucide-react";
import GoogleDriveIcon from "@/public/googledrive";
import OneDriveIcon from "@/public/onedrive";
import GoogleCloudIcon from "@/public/gcp";
import type { Source } from "@/lib/types";
import AzureIcon from "@/public/azure";
import AWSIcon from "@/public/aws";

View File

@@ -9,15 +9,7 @@ import {
import { SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar";
import { Plus, ChevronDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { ComponentType } from "react";
export interface Source {
name: string;
icon: ComponentType<{ className?: string }>;
value: string;
backgroundColor: string;
textColor?: string;
}
import type { Source } from "@/lib/types";
// ! This is a temporary implementation, will need to figure out the data to be passed from API
export default function Sources({

View File

@@ -1,13 +1,6 @@
import type { CreateRequestOptions } from "@/lib/types";
import { clientEnv } from "@/lib/env/client-env";
type Params = Record<string, string | number | null | undefined>;
type CreateRequestOptions = {
path: string;
pathParams?: Params;
queryParams?: Params;
};
/**
* Creates a request function that can be used to fetch data from an API.
* @param options - The options for the request.

View File

@@ -3,15 +3,11 @@ import { authClient } from "@nimbus/auth/auth-client";
import { useMutation } from "@tanstack/react-query";
import { clientEnv } from "@/lib/env/client-env";
import { useState, useCallback } from "react";
import type { AuthState } from "@/lib/types";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import axios from "axios";
interface AuthState {
isLoading: boolean;
error: string | null;
}
export const signInWithGoogle = async () => {
await authClient.signIn.social({
provider: "google",

View File

@@ -1,12 +1,9 @@
import { useMutation } from "@tanstack/react-query";
import type { DeleteFileParams } from "@/lib/types";
import { clientEnv } from "@/lib/env/client-env";
import axios, { type AxiosError } from "axios";
import { toast } from "sonner";
interface DeleteFileParams {
id: string;
}
export function useFileOperations() {
const deleteFileMutation = useMutation({
mutationFn: async ({ id }: DeleteFileParams) => {

View File

@@ -1,19 +1,7 @@
import type { UseRequestParams, UseRequestReturn } from "@/lib/types";
import { useCallback, useEffect, useRef, useState } from "react";
import { parseError } from "@/utils/error";
type UseRequestParams = {
request: (signal: AbortSignal) => Promise<Response>;
triggers?: unknown[];
manual?: boolean;
};
type UseRequestReturn<ResponseBody> = {
data: ResponseBody | null;
error: Error | null;
isLoading: boolean;
refetch: () => void;
};
/**
* A hook that fetches data from an API and returns the data, refetch function, error, and loading state.
* @param options - The options for the request.

View File

@@ -1,24 +1,11 @@
// TODO: Move to useFileOperations.ts
import type { CreateFolderParams } from "@/lib/types";
import { useMutation } from "@tanstack/react-query";
import { clientEnv } from "@/lib/env/client-env";
import axios, { type AxiosError } from "axios";
import { useState } from "react";
import { toast } from "sonner";
import axios from "axios";
type AxiosError = {
response?: {
data?: {
message?: string;
};
};
message: string;
};
interface CreateFolderParams {
name: string;
parentId?: string;
}
export function useUpload() {
const [uploadFileOpen, setUploadFileOpen] = useState(false);
@@ -60,7 +47,7 @@ export function useUpload() {
},
onError: (error: AxiosError) => {
console.error("Error creating folder:", error);
const errorMessage = error.response?.data?.message || error.message || "Failed to create folder";
const errorMessage = error.message || "Failed to create folder";
toast.error(errorMessage);
},
});

View File

@@ -1,4 +1,12 @@
// TODO: Turn this into the typing file for the front end
// This file holds all the custom interfaces and types for the Next.js front end app.
import type { ChangeEvent, ComponentProps, ComponentType, ReactNode } from "react";
import type { Button } from "@/components/ui/button";
import type { Input } from "@/components/ui/input";
import type { ChangeEvent, ComponentProps, ComponentType, ReactNode } from "react";
import type { Button } from "@/components/ui/button";
import type { Input } from "@/components/ui/input";
export interface FileItem {
id: string;
@@ -7,3 +15,82 @@ export interface FileItem {
size?: string;
modified: string;
}
export interface CreateFolderDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onCreateFolder: (folderName: string, parentId?: string | undefined) => void;
}
export interface UploadFileDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onUpload: (files: FileList) => void;
}
export interface FolderContentItem extends FileItem {
path?: string;
}
export interface Source {
name: string;
icon: ComponentType<{ className?: string }>;
value: string;
backgroundColor: string;
textColor?: string;
}
export interface AuthState {
isLoading: boolean;
error: string | null;
}
export interface DeleteFileParams {
id: string;
}
export interface AuthCardProps extends ComponentProps<"div"> {
title: string;
description: string;
navigationType: "signin" | "signup";
children: ReactNode;
}
export type Params = Record<string, string | number | null | undefined>;
export type CreateRequestOptions = {
path: string;
pathParams?: Params;
queryParams?: Params;
};
export type UseRequestParams = {
request: (signal: AbortSignal) => Promise<Response>;
triggers?: unknown[];
manual?: boolean;
};
export type UseRequestReturn<ResponseBody> = {
data: ResponseBody | null;
error: Error | null;
isLoading: boolean;
refetch: () => Promise<void>;
};
export interface CreateFolderParams {
name: string;
parentId?: string;
}
export type SocialProvider = "google";
export type AuthAction = "signin" | "signup";
export interface SocialAuthButtonProps extends Omit<ComponentProps<typeof Button>, "children" | "variant" | "type"> {
provider: SocialProvider;
action: AuthAction;
}
export interface PasswordInputProps extends Omit<ComponentProps<typeof Input>, "type"> {
value?: string;
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}