refactor: add CardBase and ModalBase components

- Add CardBase: reusable card with header, content, footer
  - Configurable via props: padding, border, text size, background
- Add ModalBase: modal wrapper using CardBase internally
  - Provides backdrop, click-outside-to-close, Android back button
- Refactor EventCardBase to use CardBase
- Refactor DeleteEventModal to use ModalBase
- Refactor EventOverlay (calendar.tsx) to use ModalBase
- Update CLAUDE.md with component documentation
This commit is contained in:
2026-01-25 21:50:19 +01:00
parent 2b999d9b0f
commit 726334c155
7 changed files with 366 additions and 265 deletions

View File

@@ -1,11 +1,4 @@
import {
Animated,
Modal,
Pressable,
Text,
View,
ScrollView,
} from "react-native";
import { Animated, Modal, Pressable, Text, View } from "react-native";
import {
DAYS,
MONTHS,
@@ -16,6 +9,7 @@ import {
import Header from "../../components/Header";
import { EventCard } from "../../components/EventCard";
import { DeleteEventModal } from "../../components/DeleteEventModal";
import { ModalBase } from "../../components/ModalBase";
import React, {
useCallback,
useEffect,
@@ -263,7 +257,6 @@ const EventOverlay = ({
onEditEvent,
onDeleteEvent,
}: EventOverlayProps) => {
const { theme } = useThemeStore();
if (!date) return null;
const dateString = date.toLocaleDateString("de-DE", {
@@ -273,75 +266,27 @@ const EventOverlay = ({
year: "numeric",
});
const subtitle = `${events.length} ${events.length === 1 ? "Termin" : "Termine"}`;
return (
<Modal
<ModalBase
visible={visible}
transparent={true}
animationType="fade"
onRequestClose={onClose}
onClose={onClose}
title={dateString}
subtitle={subtitle}
footer={{ label: "Schliessen", onPress: onClose }}
scrollable={true}
maxContentHeight={400}
>
<Pressable
className="flex-1 justify-center items-center"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
onPress={onClose}
>
<Pressable
className="w-11/12 max-h-3/4 rounded-2xl overflow-hidden"
style={{
backgroundColor: theme.primeBg,
borderWidth: 4,
borderColor: theme.borderPrimary,
}}
onPress={(e) => e.stopPropagation()}
>
{/* Header */}
<View
className="px-4 py-3"
style={{
backgroundColor: theme.chatBot,
borderBottomWidth: 3,
borderBottomColor: theme.borderPrimary,
}}
>
<Text
className="font-bold text-lg"
style={{ color: theme.textPrimary }}
>
{dateString}
</Text>
<Text style={{ color: theme.textPrimary }}>
{events.length} {events.length === 1 ? "Termin" : "Termine"}
</Text>
</View>
{/* Events List */}
<ScrollView className="p-4" style={{ maxHeight: 400 }}>
{events.map((event, index) => (
<EventCard
key={`${event.id}-${index}`}
event={event}
onEdit={() => onEditEvent(event)}
onDelete={() => onDeleteEvent(event)}
/>
))}
</ScrollView>
{/* Close button */}
<Pressable
onPress={onClose}
className="py-3 items-center"
style={{
borderTopWidth: 1,
borderTopColor: theme.placeholderBg,
}}
>
<Text style={{ color: theme.primeFg }} className="font-bold">
Schließen
</Text>
</Pressable>
</Pressable>
</Pressable>
</Modal>
{events.map((event, index) => (
<EventCard
key={`${event.id}-${index}`}
event={event}
onEdit={() => onEditEvent(event)}
onDelete={() => onDeleteEvent(event)}
/>
))}
</ModalBase>
);
};