-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
--- <details open="true"><summary>Generated summary (powered by <a href="https://app.graphite.dev">Graphite</a>)</summary> > ## TL;DR > This pull request includes various changes to the codebase. It adds a file router for handling file uploads, updates the StreamPlayer component to include an InfoCard component, and introduces an InfoModal component for editing stream information. It also includes updates to dependencies and the addition of new files. > > ## What changed > - Added a file router for handling file uploads > - Updated the StreamPlayer component to include an InfoCard component > - Introduced an InfoModal component for editing stream information > - Added new files: "info-modal.tsx", "separator.tsx", "uploadthing.ts" > > ## How to test > 1. Test the file router by uploading different file types and checking if the permissions and file types are set correctly. > 2. Test the StreamPlayer component by rendering it and verifying that the InfoCard component displays the stream information correctly. > 3. Test the InfoModal component by rendering it and checking if the form for editing stream information works as expected. > 4. Test the functionality of the InfoCard component by passing different props such as name, thumbnailUrl, hostIdentity, and viewerIdentity and verifying that the component renders correctly. > 5. Test the InfoModal component by passing initialName and initialThumbnailUrl props and checking if the state variables are initialized correctly. > 6. Test the conditional rendering by checking if the div element with specific styling or the UploadDropzone component is displayed based on the condition. > 7. Test the form dialog by triggering the dialog box, entering values in the input fields, and submitting the form to update the stream information. > 8. Test the Label and Separator components by rendering them and verifying that they apply the specified styles correctly. > 9. Test the dependencies and peer dependencies by running the application and checking if all the required packages are installed and functioning correctly. > > ## Why make this change > - The file router is necessary for handling file uploads and setting permissions and file types for the file route. > - The InfoCard component provides important information about the stream and enhances the functionality of the StreamPlayer component. > - The InfoModal component allows users to edit stream information, improving the user experience. > - The updates to dependencies ensure that the codebase is up to date and compatible with the latest versions of the required packages. </details>
- Loading branch information
Showing
12 changed files
with
463 additions
and
22 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,33 @@ | ||
import { getSelf } from "@/lib/auth-service"; | ||
import { db } from "@/lib/db"; | ||
import { createUploadthing, type FileRouter } from "uploadthing/next"; | ||
|
||
const f = createUploadthing(); | ||
|
||
// FileRouter for your app, can contain multiple FileRoutes | ||
export const ourFileRouter = { | ||
// Define as many FileRoutes as you like, each with a unique routeSlug | ||
thumbnailUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 1 } }) | ||
// Set permissions and file types for this FileRoute | ||
.middleware(async () => { | ||
// This code runs on your server before upload | ||
const self = await getSelf(); | ||
|
||
return { user: self }; | ||
}) | ||
.onUploadComplete(async ({ metadata, file }) => { | ||
await db.stream.update({ | ||
where: { | ||
userId: metadata.user.id, | ||
}, | ||
data: { | ||
thumbnailUrl: file.url, | ||
}, | ||
}); | ||
|
||
// !!! Whatever is returned here is sent to the clientside `onClientUploadComplete` callback | ||
return { fileUrl: file.url }; | ||
}), | ||
} satisfies FileRouter; | ||
|
||
export type OurFileRouter = typeof ourFileRouter; |
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,8 @@ | ||
import { createNextRouteHandler } from "uploadthing/next"; | ||
|
||
import { ourFileRouter } from "./core"; | ||
|
||
// Export routes for Next App Router | ||
export const { GET, POST } = createNextRouteHandler({ | ||
router: ourFileRouter, | ||
}); |
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,62 @@ | ||
"use client"; | ||
|
||
import { Pencil } from "lucide-react"; | ||
import React from "react"; | ||
import { Separator } from "../ui/separator"; | ||
import Image from "next/image"; | ||
import { InfoModal } from "./info-modal"; | ||
|
||
interface InfoCardProps { | ||
name: string; | ||
thumbnailUrl: string | null; | ||
hostIdentity: string; | ||
viewerIdentity: string; | ||
} | ||
|
||
export const InfoCard = ({ | ||
name, | ||
thumbnailUrl, | ||
hostIdentity, | ||
viewerIdentity, | ||
}: InfoCardProps) => { | ||
return ( | ||
<div className="px-4"> | ||
<div className="rounded=xl bg-background"> | ||
<div className="flex items-center gap-x-2.5 p-4"> | ||
<div className="rounded-md bg-blue-600 p-2 h-auto w-auto"> | ||
<Pencil className="h-5 w-5" /> | ||
</div> | ||
<div> | ||
<h2 className="text-sm lg:text-lg font-semibold capitalize"> | ||
Edit your stream info | ||
</h2> | ||
<p className="text-muted-foreground text-xs lg:text-sm"> | ||
Maximize your visibility | ||
</p> | ||
</div> | ||
<InfoModal initialName={name} initialThumbnailUrl={thumbnailUrl} /> | ||
</div> | ||
<Separator /> | ||
<div className="p-4 lg:p-6 space-y-4"> | ||
<div> | ||
<h3 className="text-sm text-muted-foreground mb-2">Name</h3> | ||
<p className="text-sm font-semibold">{name}</p> | ||
</div> | ||
<div> | ||
<h3 className="text-sm text-muted-foreground mb-2">Thumbnail</h3> | ||
{thumbnailUrl && ( | ||
<div className="relative aspect-video rounded-md overflow-hidden w-[200px] border border-white/10"> | ||
<Image | ||
fill | ||
src={thumbnailUrl} | ||
alt={name} | ||
className="object-cover" | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
</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,147 @@ | ||
"use client"; | ||
|
||
import { updateStream } from "@/actions/stream"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Dialog, | ||
DialogClose, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
import { UploadDropzone } from "@/lib/uploadthing"; | ||
import Image from "next/image"; | ||
import { useRouter } from "next/navigation"; | ||
import React, { ElementRef, useRef, useState, useTransition } from "react"; | ||
import { toast } from "sonner"; | ||
import { Hint } from "../hint"; | ||
import { Trash } from "lucide-react"; | ||
|
||
interface InfoModalProps { | ||
initialName: string; | ||
initialThumbnailUrl: string | null; | ||
} | ||
|
||
export const InfoModal = ({ | ||
initialName, | ||
initialThumbnailUrl, | ||
}: InfoModalProps) => { | ||
const router = useRouter(); | ||
const closeRef = useRef<ElementRef<"button">>(null); | ||
|
||
const [isPending, startTransition] = useTransition(); | ||
const [name, setName] = useState(initialName); | ||
const [thumbnailUrl, setThumbnailUrl] = useState(initialThumbnailUrl); | ||
|
||
const onRemove = () => { | ||
startTransition(() => { | ||
updateStream({ thumbnailUrl: null }) | ||
.then(() => { | ||
toast.success("Thumbnail removed"); | ||
setThumbnailUrl(""); | ||
closeRef?.current?.click(); | ||
}) | ||
.catch(() => toast.error("Something went wrong!")); | ||
}); | ||
}; | ||
|
||
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
|
||
startTransition(() => { | ||
updateStream({ name: name }) | ||
.then(() => { | ||
toast.success("Stream settings updated"); | ||
closeRef?.current?.click(); | ||
}) | ||
.catch(() => toast.error("Something went wrong!")); | ||
}); | ||
}; | ||
|
||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
setName(e.target.value); | ||
}; | ||
|
||
return ( | ||
<Dialog> | ||
<DialogTrigger asChild> | ||
<Button variant="link" size="sm" className="ml-auto"> | ||
Edit | ||
</Button> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Edit Stream Info</DialogTitle> | ||
</DialogHeader> | ||
<form onSubmit={onSubmit} className="space-y-14"> | ||
<div className="space-y-2"> | ||
<Label>Name</Label> | ||
<Input | ||
disabled={isPending} | ||
placeholder="Stream Name" | ||
onChange={onChange} | ||
value={name} | ||
/> | ||
</div> | ||
<div className="space-y-2"> | ||
<Label>Thumbnail</Label> | ||
{thumbnailUrl ? ( | ||
<div className="relative aspect-video rounded-xl overflow-hidden border border-white/10"> | ||
<div className="absolute top-2 right-2 z-[10]"> | ||
<Hint label="Remove thumbnail" asChild side="left"> | ||
<Button | ||
type="button" | ||
disabled={isPending} | ||
onClick={onRemove} | ||
className="h-auto w-auto p-1.5" | ||
> | ||
<Trash className="h-4 w-4" /> | ||
</Button> | ||
</Hint> | ||
</div> | ||
<Image | ||
alt="thumbnail" | ||
src={thumbnailUrl} | ||
className="object-cover" | ||
fill | ||
/> | ||
</div> | ||
) : ( | ||
<div className="rounded-xl border outline-dashed outline-muted"> | ||
<UploadDropzone | ||
endpoint="thumbnailUploader" | ||
appearance={{ | ||
label: { | ||
color: "#FFFFFF", | ||
}, | ||
allowedContent: { | ||
color: "#FFFFFF", | ||
}, | ||
}} | ||
onClientUploadComplete={(res) => { | ||
setThumbnailUrl(res?.[0]?.url); | ||
router.refresh(); | ||
closeRef?.current?.click(); | ||
}} | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
<div className="flex justify-between"> | ||
<DialogClose ref={closeRef} asChild> | ||
<Button type="button" variant="ghost"> | ||
Cancel | ||
</Button> | ||
</DialogClose> | ||
<Button disabled={isPending} variant="primary" type="submit"> | ||
Save | ||
</Button> | ||
</div> | ||
</form> | ||
</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,26 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as LabelPrimitive from "@radix-ui/react-label" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const labelVariants = cva( | ||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" | ||
) | ||
|
||
const Label = React.forwardRef< | ||
React.ElementRef<typeof LabelPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & | ||
VariantProps<typeof labelVariants> | ||
>(({ className, ...props }, ref) => ( | ||
<LabelPrimitive.Root | ||
ref={ref} | ||
className={cn(labelVariants(), className)} | ||
{...props} | ||
/> | ||
)) | ||
Label.displayName = LabelPrimitive.Root.displayName | ||
|
||
export { Label } |
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,31 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as SeparatorPrimitive from "@radix-ui/react-separator" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const Separator = React.forwardRef< | ||
React.ElementRef<typeof SeparatorPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> | ||
>( | ||
( | ||
{ className, orientation = "horizontal", decorative = true, ...props }, | ||
ref | ||
) => ( | ||
<SeparatorPrimitive.Root | ||
ref={ref} | ||
decorative={decorative} | ||
orientation={orientation} | ||
className={cn( | ||
"shrink-0 bg-border", | ||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
) | ||
) | ||
Separator.displayName = SeparatorPrimitive.Root.displayName | ||
|
||
export { Separator } |
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,6 @@ | ||
import { generateComponents } from "@uploadthing/react"; | ||
|
||
import type { OurFileRouter } from "@/app/api/uploadthing/core"; | ||
|
||
export const { UploadButton, UploadDropzone, Uploader } = | ||
generateComponents<OurFileRouter>(); |
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
Oops, something went wrong.