Add media gallery with album organization and Puck integration
Backend: - Add Album and MediaFile models for tenant-scoped media storage - Add TenantStorageUsage model for per-tenant storage quota tracking - Create StorageQuotaService with EntitlementService integration - Add AlbumViewSet, MediaFileViewSet with bulk operations - Add StorageUsageView for quota monitoring Frontend: - Create MediaGalleryPage with album management and file upload - Add drag-and-drop upload with storage quota validation - Create ImagePickerField custom Puck field for gallery integration - Update Image, Testimonial components to use ImagePicker - Add background image picker to Puck design controls - Add gallery to sidebar navigation Also includes: - Puck marketing components (Hero, SplitContent, etc.) - Enhanced ContactForm and BusinessHours components - Platform login page improvements - Site builder draft/preview enhancements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ export interface TestUser {
|
||||
role: string;
|
||||
label: string;
|
||||
color: string;
|
||||
category: 'platform' | 'business' | 'customer';
|
||||
}
|
||||
|
||||
const testUsers: TestUser[] = [
|
||||
@@ -19,6 +20,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'SUPERUSER',
|
||||
label: 'Platform Superuser',
|
||||
color: 'bg-purple-600 hover:bg-purple-700',
|
||||
category: 'platform',
|
||||
},
|
||||
{
|
||||
email: 'manager@platform.com',
|
||||
@@ -26,6 +28,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'PLATFORM_MANAGER',
|
||||
label: 'Platform Manager',
|
||||
color: 'bg-blue-600 hover:bg-blue-700',
|
||||
category: 'platform',
|
||||
},
|
||||
{
|
||||
email: 'sales@platform.com',
|
||||
@@ -33,6 +36,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'PLATFORM_SALES',
|
||||
label: 'Platform Sales',
|
||||
color: 'bg-green-600 hover:bg-green-700',
|
||||
category: 'platform',
|
||||
},
|
||||
{
|
||||
email: 'support@platform.com',
|
||||
@@ -40,6 +44,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'PLATFORM_SUPPORT',
|
||||
label: 'Platform Support',
|
||||
color: 'bg-yellow-600 hover:bg-yellow-700',
|
||||
category: 'platform',
|
||||
},
|
||||
{
|
||||
email: 'owner@demo.com',
|
||||
@@ -47,6 +52,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'TENANT_OWNER',
|
||||
label: 'Business Owner',
|
||||
color: 'bg-indigo-600 hover:bg-indigo-700',
|
||||
category: 'business',
|
||||
},
|
||||
{
|
||||
email: 'manager@demo.com',
|
||||
@@ -54,6 +60,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'TENANT_MANAGER',
|
||||
label: 'Business Manager',
|
||||
color: 'bg-pink-600 hover:bg-pink-700',
|
||||
category: 'business',
|
||||
},
|
||||
{
|
||||
email: 'staff@demo.com',
|
||||
@@ -61,6 +68,7 @@ const testUsers: TestUser[] = [
|
||||
role: 'TENANT_STAFF',
|
||||
label: 'Staff Member',
|
||||
color: 'bg-teal-600 hover:bg-teal-700',
|
||||
category: 'business',
|
||||
},
|
||||
{
|
||||
email: 'customer@demo.com',
|
||||
@@ -68,14 +76,18 @@ const testUsers: TestUser[] = [
|
||||
role: 'CUSTOMER',
|
||||
label: 'Customer',
|
||||
color: 'bg-orange-600 hover:bg-orange-700',
|
||||
category: 'customer',
|
||||
},
|
||||
];
|
||||
|
||||
type UserFilter = 'all' | 'platform' | 'business';
|
||||
|
||||
interface DevQuickLoginProps {
|
||||
embedded?: boolean;
|
||||
filter?: UserFilter;
|
||||
}
|
||||
|
||||
export function DevQuickLogin({ embedded = false }: DevQuickLoginProps) {
|
||||
export function DevQuickLogin({ embedded = false, filter = 'all' }: DevQuickLoginProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const [loading, setLoading] = useState<string | null>(null);
|
||||
const [isMinimized, setIsMinimized] = useState(false);
|
||||
@@ -85,6 +97,14 @@ export function DevQuickLogin({ embedded = false }: DevQuickLoginProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter users based on the filter prop
|
||||
const filteredUsers = testUsers.filter((user) => {
|
||||
if (filter === 'all') return true;
|
||||
if (filter === 'platform') return user.category === 'platform';
|
||||
if (filter === 'business') return user.category === 'business';
|
||||
return true;
|
||||
});
|
||||
|
||||
const handleQuickLogin = async (user: TestUser) => {
|
||||
setLoading(user.email);
|
||||
try {
|
||||
@@ -174,7 +194,7 @@ export function DevQuickLogin({ embedded = false }: DevQuickLoginProps) {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{testUsers.map((user) => (
|
||||
{filteredUsers.map((user) => (
|
||||
<button
|
||||
key={user.email}
|
||||
onClick={() => handleQuickLogin(user)}
|
||||
|
||||
Reference in New Issue
Block a user