Comp/Flex days (#1074) — complete. A second leave type that does not deduct from the vacation entitlement (flextime / overtime offset). New kind column on vacay_entries, excluded from usedDays via a CASE sum; toggleEntry carries kind through service/nest/store with change-detection; desktop and mobile get a comp toolbar toggle next to the half-day one (orthogonal, so a half comp day is free); comp segments render as a diagonal hatch of the person colour, per-segment for split days (Version B). comp_used is surfaced separately in getStats. Translated into all 23 locales.
Configurable vacation year (#737) — backend only. Per-user vacay_user_settings (calendar / fiscal / anniversary), resolveYearWindow, and usedDays / compUsedDays / getStats / carry-over now computed over the leave-year [start,end) window. 'calendar' resolves byte-identically to the old date-prefix behaviour, so nothing changes for existing users and the feature is inert until the settings UI lands. Frontend (settings selector + calendar window rollover), the settings endpoint, window-aware getEntries and holiday loading are still to do — see the PR description.
// Comp/Flex days (#1074) are free — kind='comp' contributes 0 to the entitlement,
// vacation days contribute their fraction. Entries predating the column are
// 'vacation' by default. The window (#737) is the user's leave-year period; for
// 'calendar' it is Jan 1 – Dec 31, byte-identical to the old date-prefix match.
const{start,end}=resolveYearWindow(userId,year);
constrow=db.prepare(
'SELECT COALESCE(SUM(fraction), 0) AS used FROM vacay_entries WHERE user_id = ? AND plan_id = ? AND date LIKE ?'
).get(userId,planId,yearPrefix)as{used: number};
"SELECT COALESCE(SUM(CASE WHEN kind = 'comp' THEN 0 ELSE fraction END), 0) AS used FROM vacay_entries WHERE user_id = ? AND plan_id = ? AND date >= ? AND date < ?"
).get(userId,planId,start,end)as{used: number};
returnrow.used;
}
/** Comp/Flex days (#1074) used in a user's leave-year period — SUM of fractions for kind='comp'. */
constprevConfig=db.prepare('SELECT * FROM vacay_user_years WHERE user_id = ? AND plan_id = ? AND year = ?').get(u.id,planId,year-1)asVacayUserYear|undefined;
@@ -776,7 +859,7 @@ export function deleteYear(planId: number, year: number, socketId: string | unde
if(carryOverEnabled&&prevYear){
constprevConfig=db.prepare('SELECT * FROM vacay_user_years WHERE user_id = ? AND plan_id = ? AND year = ?').get(u.id,planId,prevYear.year)asVacayUserYear|undefined;
constexisting=db.prepare('SELECT id, fraction FROM vacay_entries WHERE user_id = ? AND date = ? AND plan_id = ?').get(userId,date,planId)as{id: number;fraction: number}|undefined;
constknd=normalizeKind(kind);
constexisting=db.prepare('SELECT id, fraction, kind FROM vacay_entries WHERE user_id = ? AND date = ? AND plan_id = ?').get(userId,date,planId)as{id: number;fraction: number;kind: string|null}|undefined;
if(existing){
// Clicking the same kind of day again clears it; clicking the other kind
// (full over a half, or vice versa) converts it in place.
if(existing.fraction===frac){
// Clicking the exact same day again (same type AND same fraction) clears it;
// clicking a different type or fraction converts it in place (#552/#1074).
constconfig=db.prepare('SELECT * FROM vacay_user_years WHERE user_id = ? AND plan_id = ? AND year = ?').get(u.id,planId,year)asVacayUserYear|undefined;
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.