Enhance email templates with clickable links, branding, and improved styling
- Add clickable gallery links in all email templates - Include application logo in email header and footer (custom or PicPeak default) - Redesign emails with professional styling matching gallery login page - Gray background with white content box - PicPeak green header with centered logo - Clean typography and proper spacing - Responsive design for mobile devices - Styled call-to-action buttons - Footer with branding and copyright - Update email processor to fetch branding settings dynamically - Use proper API URLs for logo images in emails 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
This commit is contained in:
@@ -25,20 +25,40 @@ interface PhotoGridWithLayoutsProps {
|
||||
photos: Photo[];
|
||||
slug: string;
|
||||
categoryId?: number | null;
|
||||
isSelectionMode?: boolean;
|
||||
selectedPhotos?: Set<number>;
|
||||
onSelectionChange?: (photos: Set<number>) => void;
|
||||
onToggleSelectionMode?: () => void;
|
||||
showSelectionControls?: boolean;
|
||||
eventName?: string;
|
||||
eventLogo?: string | null;
|
||||
}
|
||||
|
||||
export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
photos,
|
||||
slug,
|
||||
categoryId
|
||||
categoryId,
|
||||
isSelectionMode: parentSelectionMode,
|
||||
selectedPhotos: parentSelectedPhotos,
|
||||
onSelectionChange,
|
||||
onToggleSelectionMode: parentToggleSelectionMode,
|
||||
showSelectionControls = true,
|
||||
eventName,
|
||||
eventLogo
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { theme } = useTheme();
|
||||
const [selectedPhotoIndex, setSelectedPhotoIndex] = useState<number | null>(null);
|
||||
const [selectedPhotos, setSelectedPhotos] = useState<Set<number>>(new Set());
|
||||
const [isSelectionMode, setIsSelectionMode] = useState(false);
|
||||
const [localSelectedPhotos, setLocalSelectedPhotos] = useState<Set<number>>(new Set());
|
||||
const [localSelectionMode, setLocalSelectionMode] = useState(false);
|
||||
const downloadPhotoMutation = useDownloadPhoto();
|
||||
|
||||
// Use parent state if provided, otherwise use local state
|
||||
const selectedPhotos = parentSelectedPhotos ?? localSelectedPhotos;
|
||||
const isSelectionMode = parentSelectionMode ?? localSelectionMode;
|
||||
const setSelectedPhotos = onSelectionChange ?? setLocalSelectedPhotos;
|
||||
const toggleSelectionMode = parentToggleSelectionMode ?? (() => setLocalSelectionMode(!localSelectionMode));
|
||||
|
||||
// Clear selection when category changes
|
||||
useEffect(() => {
|
||||
setSelectedPhotos(new Set());
|
||||
@@ -71,10 +91,6 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const toggleSelectionMode = () => {
|
||||
setIsSelectionMode(!isSelectionMode);
|
||||
setSelectedPhotos(new Set());
|
||||
};
|
||||
|
||||
const selectAll = () => {
|
||||
setSelectedPhotos(new Set(photos.map(p => p.id)));
|
||||
@@ -112,7 +128,11 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
|
||||
// Clear selection after download
|
||||
setSelectedPhotos(new Set());
|
||||
setIsSelectionMode(false);
|
||||
if (parentToggleSelectionMode) {
|
||||
parentToggleSelectionMode();
|
||||
} else {
|
||||
setLocalSelectionMode(false);
|
||||
}
|
||||
} catch (error) {
|
||||
toastify.error(t('gallery.downloadError'));
|
||||
}
|
||||
@@ -138,6 +158,8 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
selectedPhotos,
|
||||
isSelectionMode,
|
||||
onPhotoSelect: handlePhotoSelect,
|
||||
eventName,
|
||||
eventLogo,
|
||||
};
|
||||
|
||||
let LayoutComponent;
|
||||
@@ -163,8 +185,8 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Selection Mode Controls - Not shown for carousel layout */}
|
||||
{photos.length > 1 && galleryLayout !== 'carousel' && (
|
||||
{/* Selection Mode Controls - Not shown for carousel layout or when controls are hidden */}
|
||||
{showSelectionControls && photos.length > 1 && galleryLayout !== 'carousel' && (
|
||||
<div className="mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
@@ -181,7 +203,7 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setIsSelectionMode(true);
|
||||
toggleSelectionMode();
|
||||
selectAll();
|
||||
}}
|
||||
className="text-xs sm:text-sm"
|
||||
|
||||
Reference in New Issue
Block a user