Guest User

Untitled

a guest
Sep 18th, 2024
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.99 KB | None | 0 0
  1. import { cn } from '@/lib/utils'
  2. import { Button } from './ui/button'
  3. import { useRef, useState } from 'react';
  4. import { Label } from './ui/label';
  5. import { Textarea } from './ui/textarea';
  6. import { Loader } from 'lucide-react';
  7. import { GenerateThumbnailProps } from '@/types';
  8. import { Input } from './ui/input';
  9. import Image from 'next/image';
  10. import { useToast } from './ui/use-toast';
  11. import { useAction, useMutation } from 'convex/react';
  12. import { useUploadFiles } from '@xixixao/uploadstuff/react';
  13. import { api } from '@/convex/_generated/api';
  14. import { v4 as uuidv4 } from 'uuid';
  15.  
  16. const GenerateThumbnail = ({ setImage, setImageStorageId, image, imagePrompt, setImagePrompt }: GenerateThumbnailProps) => {
  17. const [isAiThumbnail, setIsAiThumbnail] = useState(false);
  18. const [isImageLoading, setIsImageLoading] = useState(false);
  19. const imageRef = useRef<HTMLInputElement>(null); //To store Img ref
  20. const { toast } = useToast();
  21. const handleGenerateThumbnail = useAction(api.freepik.generateThumbnailAction)
  22.  
  23. //To upload Image & fetch uploaded url
  24. const generateUploadUrl = useMutation(api.files.generateUploadUrl);
  25. const { startUpload } = useUploadFiles(generateUploadUrl)
  26. const getImageUrl = useMutation(api.podcasts.getUrl);
  27.  
  28. //Image Handler Func
  29. const handleImage = async (blob: Blob, fileName: string) => {
  30. setIsImageLoading(true);
  31. setImage('');
  32.  
  33. try {
  34. const file = new File([blob], fileName, { type: 'image/png' });
  35.  
  36. const uploaded = await startUpload([file]);
  37. const storageId = (uploaded[0].response as any).storageId;
  38.  
  39. setImageStorageId(storageId);
  40.  
  41. const imageUrl = await getImageUrl({ storageId });
  42. setImage(imageUrl!);
  43. setIsImageLoading(false);
  44. toast({
  45. title: "Thumbnail generated successfully",
  46. })
  47. }
  48. catch (error) {
  49. console.log(error)
  50. toast({ title: 'Error generating thumbnail', variant: 'destructive' })
  51. setIsImageLoading(false);
  52. }
  53. }
  54.  
  55. //Custom Thumbnail
  56. const uploadImage = async (e: React.ChangeEvent<HTMLInputElement>) => {
  57. e.preventDefault();
  58.  
  59. try {
  60. const files = e.target.files;
  61. if (!files) return;
  62. const file = files[0];
  63. // If the file is very large, directly creating a Blob from it
  64. // might consume more memory than using arrayBuffer().
  65. const blob = await file.arrayBuffer()
  66. .then((ab) => new Blob([ab]));
  67.  
  68. handleImage(blob, file.name);
  69. } catch (error) {
  70. console.log(error)
  71. toast({ title: 'Error uploading image', variant: 'destructive' })
  72. }
  73. }
  74.  
  75. //AI Thumbnail
  76. const generateImage = async () => {
  77. try {
  78. const response = await handleGenerateThumbnail({ prompt: imagePrompt });
  79.  
  80. const imgResponse = await fetch(response);
  81. const blob = await imgResponse.blob();
  82. // const blob = new Blob([response], { type: 'image/png' });
  83.  
  84. handleImage(blob, `thumbnail-${uuidv4()}`);
  85.  
  86. // setImage(`data:image/png;base64,${ response }`);
  87. } catch (error) {
  88. console.log(error)
  89. toast({ title: 'Error generating thumbnail', variant: 'destructive' })
  90. }
  91. }
  92.  
  93. return (
  94. <>
  95. <div className="generate_thumbnail">
  96. <Button
  97. type="button"
  98. variant="plain"
  99. onClick={() => setIsAiThumbnail(true)}
  100. className={cn('', {
  101. 'bg-black-6': isAiThumbnail
  102. })}
  103. >
  104. Use AI to generate thumbnail
  105. </Button>
  106. <Button
  107. type="button"
  108. variant="plain"
  109. onClick={() => setIsAiThumbnail(false)}
  110. className={cn('', {
  111. 'bg-black-6': !isAiThumbnail
  112. })}
  113. >
  114. Upload custom image
  115. </Button>
  116. </div>
  117. {isAiThumbnail ? (
  118. <div className="flex flex-col gap-5">
  119. <div className="mt-5 flex flex-col gap-2.5">
  120. <Label className="text-16 font-bold text-white-1">
  121. AI Prompt to generate Thumbnail
  122. </Label>
  123. <Textarea
  124. className="input-class font-light focus-visible:ring-offset-orange-1"
  125. placeholder='Provide text to generate thumbnail'
  126. rows={5}
  127. value={imagePrompt}
  128. onChange={(e) => setImagePrompt(e.target.value)}
  129. />
  130. </div>
  131. <div className="w-full max-w-[200px]">
  132. <Button type="submit" className="text-16 bg-orange-1 py-4 font-bold text-white-1" onClick={generateImage}>
  133. {isImageLoading ? (
  134. <>
  135. Generating
  136. <Loader size={20} className="animate-spin ml-2" />
  137. </>
  138. ) : (
  139. 'Generate'
  140. )}
  141. </Button>
  142. </div>
  143. </div>
  144. ) : (
  145. <div className="image_div" onClick={() => imageRef?.current?.click()}>
  146. <Input
  147. type="file"
  148. className="hidden"
  149. ref={imageRef}
  150. onChange={(e) => uploadImage(e)}
  151. />
  152. {!isImageLoading ? (
  153. <Image src="/icons/upload-image.svg" width={40} height={40} alt="upload" />
  154. ) : (
  155. <div className="text-16 flex-center font-medium text-white-1">
  156. Uploading
  157. <Loader size={20} className="animate-spin ml-2" />
  158. </div>
  159. )}
  160. <div className="flex flex-col items-center gap-1">
  161. <h2 className="text-12 font-bold text-orange-1">
  162. Click to upload
  163. </h2>
  164. <p className="text-12 font-normal text-gray-1">SVG, PNG, JPG, or GIF (max. 1080x1080px)</p>
  165. </div>
  166. </div>
  167. )}
  168. {image && (
  169. <div className="flex-center w-full">
  170. <Image
  171. src={image}
  172. width={200}
  173. height={200}
  174. className="mt-5"
  175. alt="thumbnail"
  176. />
  177. </div>
  178. )}
  179. </>
  180. )
  181. }
  182.  
  183. export default GenerateThumbnail
Add Comment
Please, Sign In to add comment