mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 00:07:01 +00:00
fix: keep a shared calendar's own colour instead of a random one (bulwarkmail/webmail#1414)
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { autoAssignSharedCalendarColors, sharedCalendarColorKey } from '../calendar-utils';
|
||||
|
||||
describe('autoAssignSharedCalendarColors (#1414)', () => {
|
||||
const own = { id: 'c1', color: '#3b82f6' };
|
||||
const coloured = { id: 'b:c2', originalId: 'c2', accountId: 'b', isShared: true, color: '#10b981' };
|
||||
const plain = { id: 'b:c3', originalId: 'c3', accountId: 'b', isShared: true };
|
||||
|
||||
it('keeps the server colour of a shared calendar and colours only one without', () => {
|
||||
const assigned = autoAssignSharedCalendarColors([own, coloured, plain], {});
|
||||
expect(Object.keys(assigned)).toEqual([sharedCalendarColorKey(plain)]);
|
||||
const color = assigned[sharedCalendarColorKey(plain)].toLowerCase();
|
||||
expect(['#3b82f6', '#10b981']).not.toContain(color);
|
||||
});
|
||||
|
||||
it('leaves a calendar the viewer coloured alone', () => {
|
||||
expect(autoAssignSharedCalendarColors([plain], { [sharedCalendarColorKey(plain)]: '#ef4444' })).toEqual({});
|
||||
});
|
||||
});
|
||||
@@ -617,6 +617,38 @@ export function pickUnusedCalendarColor(usedColors: Iterable<string>): string {
|
||||
* via the `colorIsLocalOverride` flag (see getEventColor). Personal calendars
|
||||
* are passed through untouched.
|
||||
*/
|
||||
/**
|
||||
* A distinct colour for each shared calendar that has neither a colour from
|
||||
* the server nor one the viewer picked, so several shared calendars don't
|
||||
* collide on the default colour. A shared calendar the server gives a colour
|
||||
* keeps it until the viewer picks their own (webmail #1414). Returns only the
|
||||
* new overrides, keyed by sharedCalendarColorKey().
|
||||
*/
|
||||
export function autoAssignSharedCalendarColors(
|
||||
calendars: Pick<Calendar, 'id' | 'color' | 'isShared' | 'accountId' | 'originalId'>[],
|
||||
overrides: Record<string, string>,
|
||||
): Record<string, string> {
|
||||
// Every colour already on screen: personal and server colours plus the
|
||||
// existing shared overrides.
|
||||
const used = new Set<string>();
|
||||
for (const cal of calendars) {
|
||||
if (cal.color) used.add(cal.color.toLowerCase());
|
||||
}
|
||||
for (const color of Object.values(overrides)) {
|
||||
if (color) used.add(color.toLowerCase());
|
||||
}
|
||||
const assigned: Record<string, string> = {};
|
||||
for (const cal of calendars) {
|
||||
if (!cal.isShared || cal.color) continue;
|
||||
const key = sharedCalendarColorKey(cal);
|
||||
if (overrides[key] || assigned[key]) continue;
|
||||
const color = pickUnusedCalendarColor(used);
|
||||
used.add(color.toLowerCase());
|
||||
assigned[key] = color;
|
||||
}
|
||||
return assigned;
|
||||
}
|
||||
|
||||
export function applySharedCalendarColors(
|
||||
calendars: Calendar[],
|
||||
overrides: Record<string, string>,
|
||||
|
||||
@@ -87,7 +87,7 @@ import {
|
||||
getEventStartDate,
|
||||
getPrimaryCalendarId,
|
||||
getTaskDueDate,
|
||||
pickUnusedCalendarColor,
|
||||
autoAssignSharedCalendarColors,
|
||||
sharedCalendarColorKey,
|
||||
reopenedEdit,
|
||||
} from '../lib/calendar-utils';
|
||||
@@ -308,29 +308,13 @@ export default function CalendarScreen() {
|
||||
[storeCalendars, sharedCalendarColors],
|
||||
);
|
||||
|
||||
// Auto-assign a random, not-yet-used palette color to any freshly shared
|
||||
// calendar so multiple shared calendars don't collide on one color. Runs
|
||||
// once per calendar (guarded by the presence of an existing key), and the
|
||||
// user can still overwrite it from the sidebar.
|
||||
// Auto-assign a not-yet-used palette color to any freshly shared calendar
|
||||
// without a server colour, so multiple shared calendars don't collide on
|
||||
// one color (#1414: one with a server colour keeps it). Runs once per
|
||||
// calendar, and the user can still overwrite it from the sidebar.
|
||||
React.useEffect(() => {
|
||||
const missing = storeCalendars.filter(
|
||||
(cal) => cal.isShared && !sharedCalendarColors[sharedCalendarColorKey(cal)],
|
||||
);
|
||||
if (missing.length === 0) return;
|
||||
// Seed "used" with personal calendar colors plus already-assigned shared
|
||||
// overrides so the picks stay distinct from what's already on screen.
|
||||
const used = new Set<string>();
|
||||
for (const cal of storeCalendars) {
|
||||
if (!cal.isShared && cal.color) used.add(cal.color.toLowerCase());
|
||||
}
|
||||
for (const color of Object.values(sharedCalendarColors)) {
|
||||
if (color) used.add(color.toLowerCase());
|
||||
}
|
||||
for (const cal of missing) {
|
||||
const color = pickUnusedCalendarColor(used);
|
||||
used.add(color.toLowerCase());
|
||||
setSharedCalendarColor(sharedCalendarColorKey(cal), color);
|
||||
}
|
||||
const assigned = autoAssignSharedCalendarColors(storeCalendars, sharedCalendarColors);
|
||||
for (const [key, color] of Object.entries(assigned)) setSharedCalendarColor(key, color);
|
||||
}, [storeCalendars, sharedCalendarColors, setSharedCalendarColor]);
|
||||
|
||||
const allCalendars = React.useMemo(
|
||||
|
||||
Reference in New Issue
Block a user