-
Notifications
You must be signed in to change notification settings - Fork 0
10:Video-Card-And-Final-Touches #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,68 @@ | ||
| import React from 'react' | ||
| "use client"; | ||
| import VideoCard from "@/components/videoCard"; | ||
| import { Video } from "@/types/interfaces"; | ||
| import axios from "axios"; | ||
| import React, { useCallback, useEffect, useState } from "react"; | ||
|
|
||
| const Home = () => { | ||
| const [videos, setVideos] = useState<Video[]>([]); | ||
| const [loading, setLoading] = useState(true); | ||
| const [error, setError] = useState<string | null>(null); | ||
|
|
||
| const fetchVideos = useCallback(async () => { | ||
| try { | ||
| const response = await axios.get("/api/videos"); | ||
| if (Array.isArray(response.data)) { | ||
| setVideos(response.data); | ||
| } else { | ||
| throw new Error("Unexpected response Format"); | ||
| } | ||
| } catch (error) { | ||
| console.log(error); | ||
| setError("Failed to fetch videos"); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| fetchVideos(); | ||
| }, [fetchVideos]); | ||
|
|
||
| const handleDownload = useCallback(async (url: string, title: string) => { | ||
| const link = document.createElement("a"); | ||
| link.href = url; | ||
| link.setAttribute("download", `${title}.mp4`); | ||
| link.setAttribute("target", "_blank"); | ||
| document.body.appendChild(link); | ||
| link.click(); | ||
| document.body.removeChild(link); | ||
| }, []); | ||
|
|
||
| if (loading) { | ||
| return <div>Loading...</div>; | ||
| } | ||
|
|
||
| return ( | ||
| <div>Home</div> | ||
| ) | ||
| } | ||
| <div className="container mx-auto p-4 "> | ||
| <h1 className="text-2xl font-bold mb-4">Videos</h1> | ||
| {videos.length === 0 ? ( | ||
| <div className="text-center text-lg text-gray-500"> | ||
| No Videos available | ||
| </div> | ||
| ) : ( | ||
| <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> | ||
| {videos.map((video) => ( | ||
| <VideoCard | ||
| key={video.publicId} | ||
| video={video} | ||
| onDownload={handleDownload} | ||
| /> | ||
| ))} | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Home | ||
| export default Home; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| "use client" | ||
| import { useClerk, useUser } from "@clerk/nextjs"; | ||
| import { ImageIcon,LogOutIcon, MenuIcon } from "lucide-react"; | ||
| import Image from "next/image"; | ||
| import Link from "next/link"; | ||
| import { usePathname, useRouter } from "next/navigation"; | ||
| import React, { useState } from "react"; | ||
|
|
||
| import { sideBarItems } from "@/utils/constants"; | ||
|
|
||
| export default function AppLayout({ | ||
| children, | ||
| }: Readonly<{ children: React.ReactNode }>) { | ||
| const [sidebarOpen, setSidebarOpen] = useState(false); | ||
| const pathName = usePathname(); | ||
| const router = useRouter(); | ||
| const { signOut } = useClerk(); | ||
| const { user } = useUser(); | ||
|
|
||
| const handleLogoClick = () => { | ||
| router.push("/home"); | ||
| }; | ||
|
|
||
| const handleSignOut = async () => { | ||
| return await signOut; | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="drawer lg:drawer-open"> | ||
| <input | ||
| id="sidebar-drawer" | ||
| type="checkbox" | ||
| className="drawer-toggle" | ||
| checked={sidebarOpen} | ||
| onChange={() => setSidebarOpen(!sidebarOpen)} | ||
| /> | ||
| <div className="flex flex-col drawer-content "> | ||
| <header className="w-full bg-base-200"> | ||
| <div className="navbar max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | ||
| <div className="flex-none lg:hidden"> | ||
| <label | ||
| htmlFor="sidebar-drawer" | ||
| className="btn btn-square btn-ghost drawer-button" | ||
| > | ||
| <MenuIcon /> | ||
| </label> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <Link href={"/home"} onClick={handleLogoClick}> | ||
| <div className="btn btn-ghost normal-case text-2xl font-bold tracking-tight cursor-pointer"> | ||
| Cloudinary Showcase | ||
| </div> | ||
| </Link> | ||
| </div> | ||
| <div className="flex flex-none items-center space-x-4"> | ||
| {user && ( | ||
| <> | ||
| <div className="avatar"> | ||
| <div className="w-8 h-8 rounded-full"> | ||
| <Image | ||
| src={user.imageUrl} | ||
| width={8} | ||
| height={8} | ||
| alt={ | ||
| user.username || user.emailAddresses[0].emailAddress | ||
| } | ||
| /> | ||
| </div> | ||
| </div> | ||
| <span className="text-sm truncate max-w-xs lg:max-w-md"> | ||
| {user.username || user.emailAddresses[0].emailAddress} | ||
| </span> | ||
| <button | ||
| onClick={handleSignOut} | ||
| className="btn btn-ghost btn-circle" | ||
| > | ||
| <LogOutIcon className="h-6 w-6" /> | ||
| </button> | ||
| </> | ||
| )} | ||
| </div> | ||
| </div> | ||
| </header> | ||
| <main className="flex-grow"> | ||
| <div className="max-w-7xl mx-auto w-full px-4 sm:px-6 lg:px-8 my-8"> | ||
| {children} | ||
| </div> | ||
| </main> | ||
| </div> | ||
| <div className="drawer-side"> | ||
| <label htmlFor="sidebar-drawer" className="drawer-overlay"></label> | ||
| <aside className="w-64 h-full flex flex-col bg-base-200 "> | ||
| <div className="flex items-center justify-center py-4"> | ||
| <ImageIcon className="w-10 h-10 text-primary" /> | ||
| </div> | ||
| <ul className="w-full grow text-base-content menu p-4 "> | ||
| {sideBarItems.map((item) => ( | ||
| <li key={item.href} className="mb-2"> | ||
| <Link | ||
| href={item.href} | ||
| className={`flex items-center space-x-4 px-4 py-2 rounded-lg ${pathName === item.href ? "bg-primary text-white" : "hover:bg-base-300"}`} | ||
| onClick={() => setSidebarOpen(false)} | ||
| > | ||
| <item.icon className="w-6 h-6"/> | ||
| <span>{item.label}</span> | ||
| </Link> | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| {user && ( | ||
| <div className="p-4"> | ||
| <button className="btn btn-outline btn-error w-full" onClick={handleSignOut}> | ||
| <LogOutIcon className="mr-2 h-5 w-5"/> | ||
| Sign Out | ||
| </button> | ||
| </div> | ||
| )} | ||
| </aside> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,154 @@ | ||||||||||||||||||||||||||||||||||
| import React from 'react' | ||||||||||||||||||||||||||||||||||
| "use client"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import React, { useEffect, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||
| import { CldImage } from "next-cloudinary"; | ||||||||||||||||||||||||||||||||||
| import { socialFormats } from "@/utils/constants"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| type SocialFormat = keyof typeof socialFormats; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| export default function Soical() { | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Fix the spelling of "Social". The component name ✏️ Proposed fix-export default function Soical() {
+export default function Social() {- Soical Media Image Creator
+ Social Media Image Creator- <h2>Select social Media format</h2>
+ <h2>Select Social Media Format</h2>Note: Also applies to: 72-72, 97-97 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| const [uploadImage, setUploadImage] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||||
| const [format, setFormat] = useState<SocialFormat>("Instagram Square (1:1)"); | ||||||||||||||||||||||||||||||||||
| const [isUploading, setIsUploading] = useState(false); | ||||||||||||||||||||||||||||||||||
| const [isTransforming, setIsTransforming] = useState(false); | ||||||||||||||||||||||||||||||||||
| const imgRef = useRef<HTMLImageElement>(null); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||
| if (uploadImage) { | ||||||||||||||||||||||||||||||||||
| setIsTransforming(true) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| }, [format, uploadImage]); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const handleFileUpload = async ( | ||||||||||||||||||||||||||||||||||
| event: React.ChangeEvent<HTMLInputElement>, | ||||||||||||||||||||||||||||||||||
| ) => { | ||||||||||||||||||||||||||||||||||
| const file = event.target.files?.[0]; | ||||||||||||||||||||||||||||||||||
| if (!file) return; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| setIsUploading(true); | ||||||||||||||||||||||||||||||||||
| const formData = new FormData(); | ||||||||||||||||||||||||||||||||||
| formData.append("file", file); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| const response = await fetch("api/upload-image", { | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Use an absolute API path.
🐛 Proposed fix- const response = await fetch("api/upload-image", {
+ const response = await fetch("/api/upload-image", {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||||||||||||||||
| body: formData, | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!response.ok) throw new Error("Failed to upload image"); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const data = await response.json(); | ||||||||||||||||||||||||||||||||||
| setUploadImage(data?.publicId); | ||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||
| console.error(error); | ||||||||||||||||||||||||||||||||||
| alert("Failed to upload image"); | ||||||||||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||||||||||
| setIsUploading(false); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const handleDownload = async () => { | ||||||||||||||||||||||||||||||||||
| if (!imgRef.current) return; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| await fetch(imgRef.current.src) | ||||||||||||||||||||||||||||||||||
| .then((response) => response.blob()) | ||||||||||||||||||||||||||||||||||
| .then((blob) => { | ||||||||||||||||||||||||||||||||||
| const url = window.URL.createObjectURL(blob); | ||||||||||||||||||||||||||||||||||
| const link = document.createElement("a"); | ||||||||||||||||||||||||||||||||||
| link.href = url; | ||||||||||||||||||||||||||||||||||
| link.download = `${format.replace(/\s+/g, "_").toLowerCase()}.png`; | ||||||||||||||||||||||||||||||||||
| document.body.appendChild(link); | ||||||||||||||||||||||||||||||||||
| link.click(); | ||||||||||||||||||||||||||||||||||
| document.body.removeChild(link); | ||||||||||||||||||||||||||||||||||
| window.URL.revokeObjectURL(url); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const Social = () => { | ||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| <div>Social</div> | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||
| <main> | ||||||||||||||||||||||||||||||||||
| <div className="container mx-auto p-4 max-w-4xl"> | ||||||||||||||||||||||||||||||||||
| <h1 className="text-3xl font-bold mb-6 text-center"> | ||||||||||||||||||||||||||||||||||
| Soical Media Image Creator | ||||||||||||||||||||||||||||||||||
| </h1> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="card"> | ||||||||||||||||||||||||||||||||||
| <div className="card-body"> | ||||||||||||||||||||||||||||||||||
| <h2 className="card-title">Upload an Image</h2> | ||||||||||||||||||||||||||||||||||
| <div className="form-control"> | ||||||||||||||||||||||||||||||||||
| <label className="label"> | ||||||||||||||||||||||||||||||||||
| <span className="label-text">Choose an image file</span> | ||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||
| type="file" | ||||||||||||||||||||||||||||||||||
| onChange={handleFileUpload} | ||||||||||||||||||||||||||||||||||
| className="file-input file-input-bordered file-input-primary w-full" | ||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| {isUploading && ( | ||||||||||||||||||||||||||||||||||
| <div className="mt-4"> | ||||||||||||||||||||||||||||||||||
| <progress className="progress progress-primary w-full"></progress> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| export default Social | ||||||||||||||||||||||||||||||||||
| {uploadImage && ( | ||||||||||||||||||||||||||||||||||
| <div className="mt-6"> | ||||||||||||||||||||||||||||||||||
| <h2>Select social Media format</h2> | ||||||||||||||||||||||||||||||||||
| <div className="form-control"> | ||||||||||||||||||||||||||||||||||
| <select | ||||||||||||||||||||||||||||||||||
| className="select select-bordered w-full" | ||||||||||||||||||||||||||||||||||
| value={format} | ||||||||||||||||||||||||||||||||||
| onChange={(e) => | ||||||||||||||||||||||||||||||||||
| setFormat(e.target.value as SocialFormat) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||
| {Object.keys(socialFormats).map((fmt) => ( | ||||||||||||||||||||||||||||||||||
| <option key={fmt} value={fmt}> | ||||||||||||||||||||||||||||||||||
| {fmt} | ||||||||||||||||||||||||||||||||||
| </option> | ||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||
| </select> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="mt-6 relative"> | ||||||||||||||||||||||||||||||||||
| <h3 className="text-lg font-semibold mb-2">Preview: </h3> | ||||||||||||||||||||||||||||||||||
| <div className="flex justify-center"> | ||||||||||||||||||||||||||||||||||
| {isTransforming && ( | ||||||||||||||||||||||||||||||||||
| <div className="absolute inset-0 flex items-center justify-center bg-base-100 bg-opacity-50 z-10"> | ||||||||||||||||||||||||||||||||||
| <span className="loading loading-spinner loading-lg"></span> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+114
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: In Tailwind CSS v4, the standalone bg-opacity-* utilities have been removed [1][2]. The slash syntax (e.g., bg-black/50) is now the required standard for controlling background opacity [1][3]. This change is part of a broader simplification in v4 where many deprecated utilities—including text-opacity-, border-opacity-, divide-opacity-, ring-opacity-, and placeholder-opacity-*—were removed in favor of unified opacity modifiers [1][4]. Key details regarding this change: - Migration: Projects upgrading from v3 to v4 must replace existing usages of legacy opacity classes with the slash modifier syntax [1][3]. Note that automated migration tools may not always catch these specific patterns, requiring manual review [5][4]. - Functionality: The slash modifier works by applying the specified opacity directly to the color value (using modern CSS color-mix under the hood) [6]. For example, changing bg-blue-500 bg-opacity-50 to bg-blue-500/50 [3]. - Customization: If your project requires the legacy behavior, it is possible to reintroduce these utilities manually using the Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== package files containing tailwind dependency =="
git ls-files | rg '(^|/)(package.json|package-lock.json|yarn.lock|pnpm-lock.yaml|bun.lockb|bun.lock)$' || true
if [ -f package.json ]; then
node -e "const p=require('./package.json'); console.log(JSON.stringify({dependencies:p.dependencies?.tailwindcss, devDependencies:p.devDependencies?.tailwindcss}, null, 2))"
fi
echo
echo "== locate target file =="
fd -a 'page\.tsx$' . | rg 'social/page\.tsx$' || true
echo
echo "== target snippet =="
if [ -f 'app/(app)/social/page.tsx' ]; then
sed -n '100,135p' 'app/(app)/social/page.tsx' | nl -ba -v100
fi
echo
echo "== search bg-opacity usage in target =="
if [ -f 'app/(app)/social/page.tsx' ]; then
rg -n 'bg-opacity-50|bg-base-100/50|loading-spinner|bg-base-100' 'app/(app)/social/page.tsx'
fi
echo
echo "== tailwind docs availability =="
if [ -d node_modules/next/dist/docs ]; then
find node_modules/next/dist/docs -maxdepth 2 -type f | sort | head -50
else
echo "node_modules/next/dist/docs not present"
fiRepository: CodingWithTushar/learningsaas Length of output: 417 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import re, pathlib, json
path = pathlib.Path("app/(app)/social/page.tsx")
if path.exists():
text = path.read_text()
m = re.search(r'<div className=["\']mt-6 relative["\']>(.*?)</div>\n\s*</div>', text, re.S)
if m:
block = m.group(1)
print("Overlay block found")
print(repr(block[:300]))
# Find any semantic heading before the absolute overlay inside this block/start-of-block context.
heading = re.search(r'<h3\b[^>]*>Preview[:\s]*\s*</h3>', block)
absolute = re.search(r'<div\s+className=["\']absolute\s+inset-0\b', block)
if heading and absolute:
print("has_heading_before_overlay=", heading.start() < absolute.start())
# Extract overlay classes
om = re.search(r'<div\s+className=["\']([^"\']*\babsolute\b[^"\']*)["\']\s+...', block)
if om:
classes = om.group(1).split()
print("overlay_classes=", classes)
print("inset_0_present=", "inset-0" in classes)
print("bg_opacity_50_present=", any(c.startswith("bg-opacity-50") or c=="bg-opacity-50" for c in classes))
print("bg_base_100_slash_50_present=", any(c.startswith("bg-base-100/50") or c=="bg-base-100/50" for c in classes))
PYRepository: CodingWithTushar/learningsaas Length of output: 527 Replace the unsupported Tailwind v4.3.2 does not emit 🐛 Proposed fix- <div className="absolute inset-0 flex items-center justify-center bg-base-100 bg-opacity-�[31m50�[m z-10">
+ <div className="absolute inset-0 flex items-center justify-center bg-base-100/50 z-10">📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <CldImage | ||||||||||||||||||||||||||||||||||
| width={socialFormats[format].width} | ||||||||||||||||||||||||||||||||||
| height={socialFormats[format].height} | ||||||||||||||||||||||||||||||||||
| src={uploadImage} | ||||||||||||||||||||||||||||||||||
| sizes="100vw" | ||||||||||||||||||||||||||||||||||
| alt="transformed image" | ||||||||||||||||||||||||||||||||||
| crop={"fill"} | ||||||||||||||||||||||||||||||||||
| aspectRatio={socialFormats[format].aspectRatio} | ||||||||||||||||||||||||||||||||||
| gravity="auto" | ||||||||||||||||||||||||||||||||||
| ref={imgRef} | ||||||||||||||||||||||||||||||||||
| onLoad={() => setIsTransforming(false)} | ||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="card-actions justify-end mt-6 "> | ||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||
| className="btn btn-primary" | ||||||||||||||||||||||||||||||||||
| onClick={handleDownload} | ||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||
| Download for {format} | ||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </main> | ||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: CodingWithTushar/learningsaas
Length of output: 218
🏁 Script executed:
Repository: CodingWithTushar/learningsaas
Length of output: 258
🏁 Script executed:
Repository: CodingWithTushar/learningsaas
Length of output: 2827
Remove the leftover root route page.
app/page.tsxexports a differentHomecomponent that returns<></>, so the/route still exists alongsideapp/(app)/home/page.tsx. Delete or replaceapp/page.tsxif it is not an intentional route.🧰 Tools
🪛 ESLint
[error] 29-29: Error: Calling setState synchronously within an effect can trigger cascading renders
Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).
/home/jailuser/git/app/(app)/home/page.tsx:29:5
27 |
28 | useEffect(() => {
(react-hooks/set-state-in-effect)
🤖 Prompt for AI Agents