feat: home page banner crud #46
@@ -84,7 +84,7 @@ export default function HomepageBannerModal({
|
|||||||
<Label className="font-semibold">Desktop Media URL</Label>
|
<Label className="font-semibold">Desktop Media URL</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{bannerForm.mediaType === 'VIDEO'
|
{bannerForm.mediaType === 'VIDEO'
|
||||||
? 'Recommended: 16:9 MP4 Format'
|
? 'Recommended: 1920 × 650 MP4 Format '
|
||||||
: 'Recommended: 1920 × 650 Widescreen'}
|
: 'Recommended: 1920 × 650 Widescreen'}
|
||||||
</p>
|
</p>
|
||||||
<BytescaleUploader
|
<BytescaleUploader
|
||||||
@@ -102,9 +102,7 @@ export default function HomepageBannerModal({
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="font-semibold">Mobile Media URL (Optional)</Label>
|
<Label className="font-semibold">Mobile Media URL (Optional)</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{bannerForm.mediaType === 'VIDEO'
|
{bannerForm.mediaType === 'VIDEO' ? 'Recommended: 340 × 390 MP4 Format' : 'Recommended: 340 × 390 '}
|
||||||
? 'Recommended: 9:16 Vertical Video'
|
|
||||||
: 'Recommended: 750 × 1000 Portrait'}
|
|
||||||
</p>
|
</p>
|
||||||
<BytescaleUploader
|
<BytescaleUploader
|
||||||
value={bannerForm.mobileMediaUrl || ''}
|
value={bannerForm.mobileMediaUrl || ''}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { User, X, Loader2 } from 'lucide-react';
|
import { User, X, Loader2, Video } from 'lucide-react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
interface BytescaleUploaderProps {
|
interface BytescaleUploaderProps {
|
||||||
@@ -22,12 +22,19 @@ export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUplo
|
|||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const isVideo = (url: string) => {
|
||||||
|
return /\.(mp4|webm|ogg)$/i.test(url);
|
||||||
|
};
|
||||||
|
|
||||||
const onFileSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
const onFileSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
|
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
if (file.size > 5 * 1024 * 1024) {
|
const maxSize = file.type.startsWith('video/') ? 10 * 1024 * 1024 : 5 * 1024 * 1024;
|
||||||
alert('File is too large (Max 5MB)');
|
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
alert(file.type.startsWith('video/') ? 'Video is too large (Max 10MB)' : 'Image is too large (Max 5MB)');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +59,10 @@ export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUplo
|
|||||||
alert(`Upload Error: ${errorMessage}`);
|
alert(`Upload Error: ${errorMessage}`);
|
||||||
} finally {
|
} finally {
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
if (fileInputRef.current) fileInputRef.current.value = '';
|
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.value = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,11 +72,16 @@ export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUplo
|
|||||||
<div className="relative">
|
<div className="relative">
|
||||||
{value ? (
|
{value ? (
|
||||||
<>
|
<>
|
||||||
<img
|
{isVideo(value) ? (
|
||||||
src={value}
|
<video src={value} className="w-20 h-20 rounded-md object-cover border-2 border-primary/20" controls />
|
||||||
className="w-16 h-16 rounded-full object-cover border-2 border-primary/20"
|
) : (
|
||||||
alt="Preview"
|
<img
|
||||||
/>
|
src={value}
|
||||||
|
className="w-16 h-16 rounded-full object-cover border-2 border-primary/20"
|
||||||
|
alt="Preview"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onChange('')}
|
onClick={() => onChange('')}
|
||||||
@@ -90,7 +105,7 @@ export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUplo
|
|||||||
type="file"
|
type="file"
|
||||||
ref={fileInputRef}
|
ref={fileInputRef}
|
||||||
onChange={onFileSelected}
|
onChange={onFileSelected}
|
||||||
accept="image/jpeg,image/png,image/webp"
|
accept="image/jpeg,image/png,image/webp,video/mp4,video/webm,video/ogg"
|
||||||
className="hidden"
|
className="hidden"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -107,9 +122,9 @@ export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUplo
|
|||||||
Uploading...
|
Uploading...
|
||||||
</>
|
</>
|
||||||
) : value ? (
|
) : value ? (
|
||||||
'Change Photo'
|
'Change File'
|
||||||
) : (
|
) : (
|
||||||
'Upload Photo'
|
'Upload Image / Video'
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user