refactor: extract shared EventCardBase component
- Create EventCardBase with common layout, icons (calendar, clock, repeat), and formatting functions - Refactor EventCard and ProposedEventCard to use EventCardBase - Add event details to delete action responses for better UX - Include event title in delete confirmation message
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { View, Text, Pressable } from "react-native";
|
||||
import { ProposedEventChange } from "@caldav/shared";
|
||||
import currentTheme from "../Themes";
|
||||
import { EventCardBase } from "./EventCardBase";
|
||||
|
||||
type ProposedEventCardProps = {
|
||||
proposedChange: ProposedEventChange;
|
||||
@@ -9,17 +10,52 @@ type ProposedEventCardProps = {
|
||||
onReject: () => void;
|
||||
};
|
||||
|
||||
function formatDateTime(date?: Date): string {
|
||||
if (!date) return "";
|
||||
const d = new Date(date);
|
||||
return d.toLocaleDateString("de-DE", {
|
||||
weekday: "long",
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}
|
||||
const ConfirmRejectButtons = ({
|
||||
isDisabled,
|
||||
respondedAction,
|
||||
onConfirm,
|
||||
onReject,
|
||||
}: {
|
||||
isDisabled: boolean;
|
||||
respondedAction?: "confirm" | "reject";
|
||||
onConfirm: () => void;
|
||||
onReject: () => void;
|
||||
}) => (
|
||||
<View className="flex-row mt-3 gap-2">
|
||||
<Pressable
|
||||
onPress={onConfirm}
|
||||
disabled={isDisabled}
|
||||
className="flex-1 py-2 rounded-lg items-center"
|
||||
style={{
|
||||
backgroundColor: isDisabled
|
||||
? currentTheme.disabledButton
|
||||
: currentTheme.confirmButton,
|
||||
borderWidth: respondedAction === "confirm" ? 2 : 0,
|
||||
borderColor: currentTheme.confirmButton,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: currentTheme.buttonText }} className="font-medium">
|
||||
Annehmen
|
||||
</Text>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
onPress={onReject}
|
||||
disabled={isDisabled}
|
||||
className="flex-1 py-2 rounded-lg items-center"
|
||||
style={{
|
||||
backgroundColor: isDisabled
|
||||
? currentTheme.disabledButton
|
||||
: currentTheme.rejectButton,
|
||||
borderWidth: respondedAction === "reject" ? 2 : 0,
|
||||
borderColor: currentTheme.rejectButton,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: currentTheme.buttonText }} className="font-medium">
|
||||
Ablehnen
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
|
||||
export const ProposedEventCard = ({
|
||||
proposedChange,
|
||||
@@ -30,71 +66,27 @@ export const ProposedEventCard = ({
|
||||
const event = proposedChange.event;
|
||||
const isDisabled = !!respondedAction;
|
||||
|
||||
return (
|
||||
<View
|
||||
className="border-t p-2 mt-2"
|
||||
style={{ borderTopColor: currentTheme.placeholderBg }}
|
||||
>
|
||||
{/* Event Details */}
|
||||
<Text className="font-bold text-base">{event?.title}</Text>
|
||||
<Text style={{ color: currentTheme.textSecondary }}>
|
||||
{formatDateTime(event?.startTime)}
|
||||
</Text>
|
||||
{event?.description && (
|
||||
<Text
|
||||
style={{ color: currentTheme.textSecondary }}
|
||||
className="text-sm mt-1"
|
||||
>
|
||||
{event.description}
|
||||
</Text>
|
||||
)}
|
||||
{event?.isRecurring && (
|
||||
<Text style={{ color: currentTheme.textMuted }} className="text-sm">
|
||||
Wiederkehrend
|
||||
</Text>
|
||||
)}
|
||||
if (!event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
{/* Buttons */}
|
||||
<View className="flex-row mt-3 gap-2">
|
||||
<Pressable
|
||||
onPress={onConfirm}
|
||||
disabled={isDisabled}
|
||||
className="flex-1 py-2 rounded-lg items-center"
|
||||
style={{
|
||||
backgroundColor: isDisabled
|
||||
? currentTheme.disabledButton
|
||||
: currentTheme.confirmButton,
|
||||
borderWidth: respondedAction === "confirm" ? 2 : 0,
|
||||
borderColor: currentTheme.confirmButton,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{ color: currentTheme.buttonText }}
|
||||
className="font-medium"
|
||||
>
|
||||
Annehmen
|
||||
</Text>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
onPress={onReject}
|
||||
disabled={isDisabled}
|
||||
className="flex-1 py-2 rounded-lg items-center"
|
||||
style={{
|
||||
backgroundColor: isDisabled
|
||||
? currentTheme.disabledButton
|
||||
: currentTheme.rejectButton,
|
||||
borderWidth: respondedAction === "reject" ? 2 : 0,
|
||||
borderColor: currentTheme.rejectButton,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{ color: currentTheme.buttonText }}
|
||||
className="font-medium"
|
||||
>
|
||||
Ablehnen
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
return (
|
||||
<View className="mt-2">
|
||||
<EventCardBase
|
||||
className="m-2"
|
||||
title={event.title}
|
||||
startTime={event.startTime}
|
||||
endTime={event.endTime}
|
||||
description={event.description}
|
||||
isRecurring={event.isRecurring}
|
||||
>
|
||||
<ConfirmRejectButtons
|
||||
isDisabled={isDisabled}
|
||||
respondedAction={respondedAction}
|
||||
onConfirm={onConfirm}
|
||||
onReject={onReject}
|
||||
/>
|
||||
</EventCardBase>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user