refactor: move Bytescale upload logic to backend for security

This commit is contained in:
Kailasdevdas
2026-04-16 15:33:22 +05:30
parent 5b4aacda04
commit 16cf582e2c
5 changed files with 177 additions and 40 deletions
@@ -1,7 +1,7 @@
import { useState, useRef } from "react";
import * as Bytescale from "@bytescale/sdk";
import { Button } from "@/components/ui/button";
import { User, X, Loader2 } from "lucide-react";
import {useState, useRef} from "react";
import {Button} from "@/components/ui/button";
import {User, X, Loader2} from "lucide-react";
import axios from "axios";
interface BytescaleUploaderProps {
value: string;
@@ -9,11 +9,11 @@ interface BytescaleUploaderProps {
folderPath: "/doctors" | "/departments" | "/news";
}
const uploadManager = new Bytescale.UploadManager({
apiKey: "public_223k2cv3MyaAxBeyALCfJa8EMLek",
});
export function BytescaleUploader({ value, onChange }: BytescaleUploaderProps) {
export function BytescaleUploader({
value,
onChange,
folderPath,
}: BytescaleUploaderProps) {
const [isUploading, setIsUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -21,19 +21,35 @@ export function BytescaleUploader({ value, onChange }: BytescaleUploaderProps) {
const file = event.target.files?.[0];
if (!file) return;
setIsUploading(true);
try {
const { fileUrl } = await uploadManager.upload({
data: file,
path: {
folderPath: "/doctors",
},
});
if (file.size > 5 * 1024 * 1024) {
alert("File is too large (Max 5MB)");
return;
}
setIsUploading(true);
const formData = new FormData();
formData.append("file", file);
formData.append("folderPath", folderPath);
try {
const response = await axios.post(
"http://localhost:3000/api/upload",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
},
);
const {fileUrl} = response.data;
onChange(fileUrl);
} catch (e: any) {
console.error("Upload Error:", e);
alert(`Error:\n${e.message}`);
const errorMessage =
e.response?.data?.error || e.message || "Upload failed";
alert(`Upload Error: ${errorMessage}`);
} finally {
setIsUploading(false);
if (fileInputRef.current) fileInputRef.current.value = "";
@@ -49,7 +65,7 @@ export function BytescaleUploader({ value, onChange }: BytescaleUploaderProps) {
<img
src={value}
className="w-16 h-16 rounded-full object-cover border-2 border-primary/20"
alt="Doctor Profile"
alt="Preview"
/>
<button
type="button"
@@ -100,8 +116,8 @@ export function BytescaleUploader({ value, onChange }: BytescaleUploaderProps) {
{value && (
<p className="text-xs text-amber-600 pl-[72px]">
Make sure to save the changes by clicking the "Save Changes" button
at the bottom.
Make sure to save the changes by clicking the "Save Changes"
button.
</p>
)}
</div>
+11 -11
View File
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from "react";
import { AxiosError } from "axios";
import { BytescaleUploader } from "@/components/BytescaleUploader/BytescaleUploader";
import {useState, useEffect, useCallback} from "react";
import {AxiosError} from "axios";
import {BytescaleUploader} from "@/components/BytescaleUploader/BytescaleUploader";
import {
getDepartmentsApi,
@@ -18,8 +18,8 @@ import {
TableRow,
} from "@/components/ui/table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
import {Button} from "@/components/ui/button";
import {
Dialog,
@@ -29,8 +29,8 @@ import {
DialogFooter,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import {Input} from "@/components/ui/input";
import {Textarea} from "@/components/ui/textarea";
import {
Loader2,
@@ -122,7 +122,7 @@ export default function DepartmentPage() {
);
function handleChange(e: any) {
setForm({ ...form, [e.target.name]: e.target.value });
setForm({...form, [e.target.name]: e.target.value});
}
function truncate(text: string, limit = 60) {
@@ -159,7 +159,7 @@ export default function DepartmentPage() {
async function handleSubmit() {
try {
if (editing) {
const { departmentId, ...updateData } = form;
const {departmentId, ...updateData} = form;
await updateDepartmentApi(editing.departmentId, updateData);
} else {
await createDepartmentApi(form);
@@ -402,7 +402,7 @@ export default function DepartmentPage() {
<BytescaleUploader
value={form.image}
folderPath="/departments"
onChange={(url) => setForm({ ...form, image: url })}
onChange={(url) => setForm({...form, image: url})}
/>
</div>
<Input
@@ -457,7 +457,7 @@ export default function DepartmentPage() {
Cancel
</Button>
<Button onClick={handleSubmit}>
{editing ? "Update" : "Create"}
{editing ? "Save Changes" : "Create"}
</Button>
</DialogFooter>
</DialogContent>