(sharing) add shared calendars, remove "agenda" wording

This commit is contained in:
Sylvain Zimmer
2026-02-11 23:35:46 +01:00
parent a38845e523
commit acce8d1425
4 changed files with 106 additions and 31 deletions

View File

@@ -20,7 +20,8 @@ import { extractCaldavPath } from "./utils";
export const CalendarList = () => { export const CalendarList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
davCalendars, ownedCalendars,
sharedCalendars,
visibleCalendarUrls, visibleCalendarUrls,
toggleCalendarVisibility, toggleCalendarVisibility,
createCalendar, createCalendar,
@@ -34,6 +35,7 @@ export const CalendarList = () => {
deleteState, deleteState,
shareModalState, shareModalState,
isMyCalendarsExpanded, isMyCalendarsExpanded,
isSharedCalendarsExpanded,
openMenuUrl, openMenuUrl,
handleOpenCreateModal, handleOpenCreateModal,
handleOpenEditModal, handleOpenEditModal,
@@ -47,6 +49,7 @@ export const CalendarList = () => {
handleMenuToggle, handleMenuToggle,
handleCloseMenu, handleCloseMenu,
handleToggleMyCalendars, handleToggleMyCalendars,
handleToggleSharedCalendars,
} = useCalendarListState({ } = useCalendarListState({
createCalendar, createCalendar,
updateCalendar, updateCalendar,
@@ -138,7 +141,7 @@ export const CalendarList = () => {
</div> </div>
{isMyCalendarsExpanded && ( {isMyCalendarsExpanded && (
<div className="calendar-list__items"> <div className="calendar-list__items">
{davCalendars.map((calendar) => ( {ownedCalendars.map((calendar) => (
<CalendarListItem <CalendarListItem
key={calendar.url} key={calendar.url}
calendar={calendar} calendar={calendar}
@@ -157,6 +160,50 @@ export const CalendarList = () => {
</div> </div>
)} )}
</div> </div>
{sharedCalendars.length > 0 && (
<div className="calendar-list__section">
<div className="calendar-list__section-header">
<button
className="calendar-list__toggle-btn"
onClick={handleToggleSharedCalendars}
aria-expanded={isSharedCalendarsExpanded}
>
<span
className={`material-icons calendar-list__toggle-icon ${
isSharedCalendarsExpanded
? 'calendar-list__toggle-icon--expanded'
: ''
}`}
>
expand_more
</span>
<span className="calendar-list__section-title">
{t('calendar.list.sharedCalendars')}
</span>
</button>
</div>
{isSharedCalendarsExpanded && (
<div className="calendar-list__items">
{sharedCalendars.map((calendar) => (
<CalendarListItem
key={calendar.url}
calendar={calendar}
isVisible={visibleCalendarUrls.has(calendar.url)}
isMenuOpen={openMenuUrl === calendar.url}
onToggleVisibility={toggleCalendarVisibility}
onMenuToggle={handleMenuToggle}
onEdit={handleOpenEditModal}
onDelete={handleOpenDeleteModal}
onImport={handleOpenImportModal}
onSubscription={handleOpenSubscriptionModal}
onCloseMenu={handleCloseMenu}
/>
))}
</div>
)}
</div>
)}
</div> </div>
<CalendarModal <CalendarModal

View File

@@ -47,6 +47,7 @@ export const useCalendarListState = ({
}); });
const [isMyCalendarsExpanded, setIsMyCalendarsExpanded] = useState(true); const [isMyCalendarsExpanded, setIsMyCalendarsExpanded] = useState(true);
const [isSharedCalendarsExpanded, setIsSharedCalendarsExpanded] = useState(true);
const [openMenuUrl, setOpenMenuUrl] = useState<string | null>(null); const [openMenuUrl, setOpenMenuUrl] = useState<string | null>(null);
// Modal handlers // Modal handlers
@@ -159,6 +160,10 @@ export const useCalendarListState = ({
setIsMyCalendarsExpanded((prev) => !prev); setIsMyCalendarsExpanded((prev) => !prev);
}, []); }, []);
const handleToggleSharedCalendars = useCallback(() => {
setIsSharedCalendarsExpanded((prev) => !prev);
}, []);
return { return {
// Modal state // Modal state
modalState, modalState,
@@ -167,6 +172,7 @@ export const useCalendarListState = ({
// Expansion state // Expansion state
isMyCalendarsExpanded, isMyCalendarsExpanded,
isSharedCalendarsExpanded,
openMenuUrl, openMenuUrl,
// Modal handlers // Modal handlers
@@ -190,5 +196,6 @@ export const useCalendarListState = ({
// Expansion handlers // Expansion handlers
handleToggleMyCalendars, handleToggleMyCalendars,
handleToggleSharedCalendars,
}; };
}; };

View File

@@ -48,6 +48,8 @@ export interface CalendarContextType {
caldavService: CalDavService; caldavService: CalDavService;
adapter: EventCalendarAdapter; adapter: EventCalendarAdapter;
davCalendars: CalDavCalendar[]; davCalendars: CalDavCalendar[];
ownedCalendars: CalDavCalendar[];
sharedCalendars: CalDavCalendar[];
visibleCalendarUrls: Set<string>; visibleCalendarUrls: Set<string>;
isLoading: boolean; isLoading: boolean;
isConnected: boolean; isConnected: boolean;
@@ -107,6 +109,23 @@ export const CalendarContextProvider = ({
const [currentDate, setCurrentDate] = useState<Date>(new Date()); const [currentDate, setCurrentDate] = useState<Date>(new Date());
const [selectedDate, setSelectedDate] = useState<Date>(new Date()); const [selectedDate, setSelectedDate] = useState<Date>(new Date());
const { ownedCalendars, sharedCalendars } = useMemo(() => {
const homeUrl = caldavService.getAccount()?.homeUrl;
if (!homeUrl) {
return { ownedCalendars: davCalendars, sharedCalendars: [] };
}
const owned: CalDavCalendar[] = [];
const shared: CalDavCalendar[] = [];
for (const cal of davCalendars) {
if (cal.url.startsWith(homeUrl)) {
owned.push(cal);
} else {
shared.push(cal);
}
}
return { ownedCalendars: owned, sharedCalendars: shared };
}, [davCalendars, caldavService]);
const refreshCalendars = useCallback(async () => { const refreshCalendars = useCallback(async () => {
try { try {
setIsLoading(true); setIsLoading(true);
@@ -325,6 +344,8 @@ export const CalendarContextProvider = ({
caldavService, caldavService,
adapter, adapter,
davCalendars, davCalendars,
ownedCalendars,
sharedCalendars,
visibleCalendarUrls, visibleCalendarUrls,
isLoading, isLoading,
isConnected, isConnected,

View File

@@ -804,8 +804,8 @@
} }
}, },
"list": { "list": {
"myCalendars": "Mes agendas", "myCalendars": "Mes calendriers",
"sharedCalendars": "Agendas partagés", "sharedCalendars": "Calendriers partagés",
"shared": "(partagé)", "shared": "(partagé)",
"showCalendar": "Afficher le calendrier", "showCalendar": "Afficher le calendrier",
"edit": "Modifier", "edit": "Modifier",
@@ -906,32 +906,32 @@
} }
}, },
"createCalendar": { "createCalendar": {
"title": "Créer un agenda", "title": "Créer un calendrier",
"name": "Nom", "name": "Nom",
"namePlaceholder": "Nom de l'agenda", "namePlaceholder": "Nom du calendrier",
"nameRequired": "Le nom est requis", "nameRequired": "Le nom est requis",
"color": "Couleur", "color": "Couleur",
"description": "Description", "description": "Description",
"descriptionPlaceholder": "Description de l'agenda (optionnel)", "descriptionPlaceholder": "Description du calendrier (optionnel)",
"cancel": "Annuler", "cancel": "Annuler",
"create": "Créer" "create": "Créer"
}, },
"editCalendar": { "editCalendar": {
"title": "Modifier l'agenda", "title": "Modifier le calendrier",
"save": "Enregistrer" "save": "Enregistrer"
}, },
"deleteCalendar": { "deleteCalendar": {
"title": "Supprimer l'agenda", "title": "Supprimer le calendrier",
"message": "Êtes-vous sûr de vouloir supprimer l'agenda \"{{name}}\" ? Cette action est irréversible.", "message": "Êtes-vous sûr de vouloir supprimer le calendrier \"{{name}}\" ? Cette action est irréversible.",
"confirm": "Supprimer" "confirm": "Supprimer"
}, },
"shareCalendar": { "shareCalendar": {
"title": "Partager l'agenda", "title": "Partager le calendrier",
"emailPlaceholder": "Entrez l'adresse email", "emailPlaceholder": "Entrez l'adresse email",
"share": "Partager", "share": "Partager",
"hint": "La personne aura les mêmes droits que vous (lecture et écriture).", "hint": "La personne aura les mêmes droits que vous (lecture et écriture).",
"success": "Agenda partagé avec {{email}}", "success": "Calendrier partagé avec {{email}}",
"error": "Échec du partage de l'agenda", "error": "Échec du partage du calendrier",
"invalidEmail": "Veuillez entrer une adresse email valide" "invalidEmail": "Veuillez entrer une adresse email valide"
}, },
"attendees": { "attendees": {
@@ -1109,7 +1109,7 @@
"event": { "event": {
"createTitle": "Evenement aanmaken", "createTitle": "Evenement aanmaken",
"editTitle": "Evenement bewerken", "editTitle": "Evenement bewerken",
"calendar": "Agenda", "calendar": "Kalender",
"title": "Titel", "title": "Titel",
"titlePlaceholder": "Evenement titel", "titlePlaceholder": "Evenement titel",
"location": "Locatie", "location": "Locatie",
@@ -1178,10 +1178,10 @@
} }
}, },
"list": { "list": {
"myCalendars": "Mijn agenda's", "myCalendars": "Mijn kalenders",
"sharedCalendars": "Gedeelde agenda's", "sharedCalendars": "Gedeelde kalenders",
"shared": "(gedeeld)", "shared": "(gedeeld)",
"showCalendar": "Agenda tonen", "showCalendar": "Kalender tonen",
"edit": "Bewerken", "edit": "Bewerken",
"delete": "Verwijderen", "delete": "Verwijderen",
"share": "Delen", "share": "Delen",
@@ -1202,21 +1202,21 @@
"errorDetails": "Foutdetails" "errorDetails": "Foutdetails"
}, },
"subscription": { "subscription": {
"title": "Agenda-abonnements-URL", "title": "Kalender-abonnements-URL",
"description": "Gebruik deze URL om u te abonneren op \"{{name}}\" vanuit externe agendatoepassingen (Apple Calendar, Google Calendar, Outlook, etc.).", "description": "Gebruik deze URL om u te abonneren op \"{{name}}\" vanuit externe kalendertoepassingen (Apple Calendar, Google Calendar, Outlook, etc.).",
"loading": "Abonnements-URL wordt gegenereerd...", "loading": "Abonnements-URL wordt gegenereerd...",
"copy": "Kopiëren", "copy": "Kopiëren",
"copied": "Gekopieerd!", "copied": "Gekopieerd!",
"close": "Sluiten", "close": "Sluiten",
"warning": "Deze URL bevat een privétoken. Iedereen met deze link kan uw agenda-evenementen bekijken.", "warning": "Deze URL bevat een privétoken. Iedereen met deze link kan uw kalender-evenementen bekijken.",
"regenerate": "URL regenereren", "regenerate": "URL regenereren",
"regenerateConfirm": { "regenerateConfirm": {
"title": "Abonnements-URL regenereren?", "title": "Abonnements-URL regenereren?",
"message": "Dit maakt de huidige URL ongeldig. Externe agenda's die de oude URL gebruiken zullen niet meer synchroniseren.", "message": "Dit maakt de huidige URL ongeldig. Externe kalenders die de oude URL gebruiken zullen niet meer synchroniseren.",
"confirm": "Regenereren" "confirm": "Regenereren"
}, },
"error": "Genereren van abonnements-URL mislukt. Probeer het opnieuw.", "error": "Genereren van abonnements-URL mislukt. Probeer het opnieuw.",
"errorPermission": "U heeft geen toegang tot deze agenda.", "errorPermission": "U heeft geen toegang tot deze kalender.",
"errorNetwork": "Netwerkfout. Controleer uw verbinding en probeer het opnieuw.", "errorNetwork": "Netwerkfout. Controleer uw verbinding en probeer het opnieuw.",
"errorServer": "Serverfout. Probeer het later opnieuw." "errorServer": "Serverfout. Probeer het later opnieuw."
}, },
@@ -1280,32 +1280,32 @@
} }
}, },
"createCalendar": { "createCalendar": {
"title": "Agenda aanmaken", "title": "Kalender aanmaken",
"name": "Naam", "name": "Naam",
"namePlaceholder": "Agenda naam", "namePlaceholder": "Kalender naam",
"nameRequired": "Naam is verplicht", "nameRequired": "Naam is verplicht",
"color": "Kleur", "color": "Kleur",
"description": "Beschrijving", "description": "Beschrijving",
"descriptionPlaceholder": "Agenda beschrijving (optioneel)", "descriptionPlaceholder": "Kalender beschrijving (optioneel)",
"cancel": "Annuleren", "cancel": "Annuleren",
"create": "Aanmaken" "create": "Aanmaken"
}, },
"editCalendar": { "editCalendar": {
"title": "Agenda bewerken", "title": "Kalender bewerken",
"save": "Opslaan" "save": "Opslaan"
}, },
"deleteCalendar": { "deleteCalendar": {
"title": "Agenda verwijderen", "title": "Kalender verwijderen",
"message": "Weet u zeker dat u de agenda \"{{name}}\" wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "message": "Weet u zeker dat u de kalender \"{{name}}\" wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
"confirm": "Verwijderen" "confirm": "Verwijderen"
}, },
"shareCalendar": { "shareCalendar": {
"title": "Agenda delen", "title": "Kalender delen",
"emailPlaceholder": "Voer e-mailadres in", "emailPlaceholder": "Voer e-mailadres in",
"share": "Delen", "share": "Delen",
"hint": "De persoon krijgt dezelfde rechten als u (lezen en schrijven).", "hint": "De persoon krijgt dezelfde rechten als u (lezen en schrijven).",
"success": "Agenda gedeeld met {{email}}", "success": "Kalender gedeeld met {{email}}",
"error": "Delen van agenda mislukt", "error": "Delen van kalender mislukt",
"invalidEmail": "Voer een geldig e-mailadres in" "invalidEmail": "Voer een geldig e-mailadres in"
}, },
"attendees": { "attendees": {