feat(cycle): surface the cervix secondary-symptom choice in the UI

- Advanced cycle settings gains a "secondary fertility sign" selector
  (cervical mucus default | cervix observation). It sits below the priors
  in the advanced settings so it never forces itself on a casual user.
- The log-day sheet shows the cervix entry — position / firmness / opening
  chips — only when the user picked cervix observation; otherwise the
  cervical-mucus picker stays as before. Progressive disclosure: exactly
  one secondary sign is offered at a time so the sheet never overwhelms.
- Web client types, the cyclePrefs patch, and the day-log payload builders
  carry the new fields; copy added across all six locales.
This commit is contained in:
Marc-André Bombeck committed 2026-06-14 15:33:11 +02:00
1 parent 609d248252
commit e832222402
11 files changed
+325 -15

No files matched your search

+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Eiweißartig",
"label": "Zervixschleim"
},
"cervixPosition": {
"LOW": "Tief",
"HIGH": "Hoch"
},
"cervixFirmness": {
"FIRM": "Fest",
"SOFT": "Weich"
},
"cervixOpening": {
"CLOSED": "Geschlossen",
"OPEN": "Geöffnet"
},
"goal": {
"GENERAL_HEALTH": "Allgemeine Gesundheit",
"AVOID_PREGNANCY": "Verhütung",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Fieber, Krankheit, Alkohol oder eine späte Messung — wird von der Temperaturauswertung ausgeschlossen.",
"ovulationTest": "Ovulationstest",
"mucus": "Zervixschleim",
"cervix": "Gebärmutterhals",
"cervixPosition": "Position",
"cervixFirmness": "Festigkeit",
"cervixOpening": "Öffnung",
"intercourse": "Geschlechtsverkehr",
"protected": "Geschützt",
"note": "Notiz",
@@ -5915,6 +5931,12 @@
"priorsDescription": "Diese Vorgaben helfen deinen Prognosen, bevor du viele Zyklen erfasst hast. Leer lassen, um die Standardwerte zu nutzen.",
"rawChartMode": "Roh-Diagramm-Modus",
"rawChartModeDescription": "Zeige nur deine erfassten Daten, ohne Prognosen oder Deutung.",
"secondarySymptomLabel": "Zweites Fruchtbarkeitszeichen",
"secondarySymptomDescription": "Das zweite Zeichen, das für die symptothermale Doppelkontrolle mit deiner Temperatur kombiniert wird. Die meisten beobachten den Zervixschleim; wechsle zur Gebärmutterhals-Beobachtung, wenn du das bevorzugst.",
"secondarySymptom": {
"MUCUS": "Zervixschleim",
"CERVIX": "Gebärmutterhals"
},
"prediction": "Prognosen",
"predictionDescription": "Prognostiziere deine nächste Periode und, wenn relevant, dein fruchtbares Fenster.",
"encryption": "Sensible Einträge verschlüsseln",
+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Egg white",
"label": "Cervical mucus"
},
"cervixPosition": {
"LOW": "Low",
"HIGH": "High"
},
"cervixFirmness": {
"FIRM": "Firm",
"SOFT": "Soft"
},
"cervixOpening": {
"CLOSED": "Closed",
"OPEN": "Open"
},
"goal": {
"GENERAL_HEALTH": "General health",
"AVOID_PREGNANCY": "Avoiding pregnancy",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Fever, illness, alcohol or a late measurement — excluded from the temperature evaluation.",
"ovulationTest": "Ovulation test",
"mucus": "Cervical mucus",
"cervix": "Cervix",
"cervixPosition": "Position",
"cervixFirmness": "Firmness",
"cervixOpening": "Opening",
"intercourse": "Intercourse",
"protected": "Protected",
"intermenstrualBleeding": "Spotting between periods",
@@ -5920,6 +5936,12 @@
"priorsDescription": "These priors help your predictions before you have logged many cycles. Leave blank to use the defaults.",
"rawChartMode": "Raw chart mode",
"rawChartModeDescription": "Show only your logged data with no predictions or interpretation.",
"secondarySymptomLabel": "Secondary fertility sign",
"secondarySymptomDescription": "The second sign paired with your temperature for the symptothermal double-check. Most people track cervical mucus; switch to cervix observation if you prefer.",
"secondarySymptom": {
"MUCUS": "Cervical mucus",
"CERVIX": "Cervix observation"
},
"prediction": "Predictions",
"predictionDescription": "Forecast your next period and, when relevant, your fertile window.",
"encryption": "Encrypt sensitive entries",
+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Clara de huevo",
"label": "Moco cervical"
},
"cervixPosition": {
"LOW": "Bajo",
"HIGH": "Alto"
},
"cervixFirmness": {
"FIRM": "Firme",
"SOFT": "Blando"
},
"cervixOpening": {
"CLOSED": "Cerrado",
"OPEN": "Abierto"
},
"goal": {
"GENERAL_HEALTH": "Salud general",
"AVOID_PREGNANCY": "Evitar el embarazo",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Fiebre, enfermedad, alcohol o una medición tardía: se excluye de la evaluación de temperatura.",
"ovulationTest": "Test de ovulación",
"mucus": "Moco cervical",
"cervix": "Cuello uterino",
"cervixPosition": "Posición",
"cervixFirmness": "Firmeza",
"cervixOpening": "Apertura",
"intercourse": "Relaciones",
"protected": "Protegidas",
"note": "Nota",
@@ -5915,6 +5931,12 @@
"priorsDescription": "Estos valores ayudan a tus predicciones antes de registrar muchos ciclos. Déjalos en blanco para usar los predeterminados.",
"rawChartMode": "Modo de gráfico en bruto",
"rawChartModeDescription": "Muestra solo tus datos registrados, sin predicciones ni interpretación.",
"secondarySymptomLabel": "Segundo signo de fertilidad",
"secondarySymptomDescription": "El segundo signo que se combina con tu temperatura para la doble comprobación sintotérmica. La mayoría observa el moco cervical; cambia a la observación del cuello uterino si lo prefieres.",
"secondarySymptom": {
"MUCUS": "Moco cervical",
"CERVIX": "Cuello uterino"
},
"prediction": "Predicciones",
"predictionDescription": "Pronostica tu próximo periodo y, cuando corresponda, tu ventana fértil.",
"encryption": "Cifrar entradas sensibles",
+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Blanc d'œuf",
"label": "Glaire cervicale"
},
"cervixPosition": {
"LOW": "Bas",
"HIGH": "Haut"
},
"cervixFirmness": {
"FIRM": "Ferme",
"SOFT": "Souple"
},
"cervixOpening": {
"CLOSED": "Fermé",
"OPEN": "Ouvert"
},
"goal": {
"GENERAL_HEALTH": "Santé générale",
"AVOID_PREGNANCY": "Éviter une grossesse",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Fièvre, maladie, alcool ou mesure tardive — exclue de l'évaluation de la température.",
"ovulationTest": "Test d'ovulation",
"mucus": "Glaire cervicale",
"cervix": "Col de l'utérus",
"cervixPosition": "Position",
"cervixFirmness": "Fermeté",
"cervixOpening": "Ouverture",
"intercourse": "Rapports",
"protected": "Protégés",
"note": "Note",
@@ -5915,6 +5931,12 @@
"priorsDescription": "Ces valeurs aident tes prévisions avant d'avoir enregistré beaucoup de cycles. Laisse vide pour utiliser les valeurs par défaut.",
"rawChartMode": "Mode graphique brut",
"rawChartModeDescription": "Affiche uniquement tes données enregistrées, sans prévision ni interprétation.",
"secondarySymptomLabel": "Deuxième signe de fertilité",
"secondarySymptomDescription": "Le deuxième signe associé à ta température pour la double vérification sympto-thermique. La plupart des personnes observent la glaire cervicale ; passe à l'observation du col de l'utérus si tu préfères.",
"secondarySymptom": {
"MUCUS": "Glaire cervicale",
"CERVIX": "Col de l'utérus"
},
"prediction": "Prévisions",
"predictionDescription": "Prévois tes prochaines règles et, le cas échéant, ta fenêtre fertile.",
"encryption": "Chiffrer les entrées sensibles",
+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Albume",
"label": "Muco cervicale"
},
"cervixPosition": {
"LOW": "Basso",
"HIGH": "Alto"
},
"cervixFirmness": {
"FIRM": "Duro",
"SOFT": "Morbido"
},
"cervixOpening": {
"CLOSED": "Chiuso",
"OPEN": "Aperto"
},
"goal": {
"GENERAL_HEALTH": "Salute generale",
"AVOID_PREGNANCY": "Evitare la gravidanza",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Febbre, malattia, alcol o una misurazione tardiva: esclusa dalla valutazione della temperatura.",
"ovulationTest": "Test di ovulazione",
"mucus": "Muco cervicale",
"cervix": "Cervice",
"cervixPosition": "Posizione",
"cervixFirmness": "Consistenza",
"cervixOpening": "Apertura",
"intercourse": "Rapporti",
"protected": "Protetti",
"note": "Nota",
@@ -5915,6 +5931,12 @@
"priorsDescription": "Questi valori aiutano le previsioni prima di aver registrato molti cicli. Lascia vuoto per usare i valori predefiniti.",
"rawChartMode": "Modalità grafico grezzo",
"rawChartModeDescription": "Mostra solo i tuoi dati registrati, senza previsioni né interpretazioni.",
"secondarySymptomLabel": "Secondo segno di fertilità",
"secondarySymptomDescription": "Il secondo segno abbinato alla tua temperatura per il doppio controllo sintotermico. La maggior parte osserva il muco cervicale; passa all'osservazione della cervice se preferisci.",
"secondarySymptom": {
"MUCUS": "Muco cervicale",
"CERVIX": "Cervice"
},
"prediction": "Previsioni",
"predictionDescription": "Prevedi il prossimo ciclo e, quando rilevante, la tua finestra fertile.",
"encryption": "Cifra le voci sensibili",
+22
View File
@@ -5797,6 +5797,18 @@
"EGG_WHITE": "Jak białko jaja",
"label": "Śluz szyjkowy"
},
"cervixPosition": {
"LOW": "Nisko",
"HIGH": "Wysoko"
},
"cervixFirmness": {
"FIRM": "Twarda",
"SOFT": "Miękka"
},
"cervixOpening": {
"CLOSED": "Zamknięta",
"OPEN": "Otwarta"
},
"goal": {
"GENERAL_HEALTH": "Ogólne zdrowie",
"AVOID_PREGNANCY": "Unikanie ciąży",
@@ -5886,6 +5898,10 @@
"temperatureDisturbedHint": "Gorączka, choroba, alkohol lub spóźniony pomiar — wykluczony z oceny temperatury.",
"ovulationTest": "Test owulacyjny",
"mucus": "Śluz szyjkowy",
"cervix": "Szyjka macicy",
"cervixPosition": "Położenie",
"cervixFirmness": "Twardość",
"cervixOpening": "Rozwarcie",
"intercourse": "Współżycie",
"protected": "Zabezpieczone",
"note": "Notatka",
@@ -5915,6 +5931,12 @@
"priorsDescription": "Te wartości pomagają prognozom, zanim zapiszesz wiele cykli. Zostaw puste, aby użyć wartości domyślnych.",
"rawChartMode": "Tryb surowego wykresu",
"rawChartModeDescription": "Pokazuj tylko zapisane dane, bez prognoz i interpretacji.",
"secondarySymptomLabel": "Drugi objaw płodności",
"secondarySymptomDescription": "Drugi objaw łączony z temperaturą w podwójnej kontroli objawowo-termicznej. Większość obserwuje śluz szyjkowy; przełącz na obserwację szyjki macicy, jeśli wolisz.",
"secondarySymptom": {
"MUCUS": "Śluz szyjkowy",
"CERVIX": "Szyjka macicy"
},
"prediction": "Prognozy",
"predictionDescription": "Prognozuj następną miesiączkę oraz, gdy to istotne, okno płodne.",
"encryption": "Szyfruj wrażliwe wpisy",
@@ -14,6 +14,9 @@ function blank(): DayLogFormState {
bbtDisturbed: false,
opk: null,
mucus: null,
cervixPosition: null,
cervixFirmness: null,
cervixOpening: null,
intercourse: false,
protectedSex: false,
pregnancyTest: null,
@@ -103,6 +106,24 @@ describe("buildDayLogInput (new row → omit empties)", () => {
expect(patch.temperatureExcluded).toBe(true);
});
it("carries the cervix signs through both payload builders", () => {
const state = {
...blank(),
cervixPosition: "HIGH" as const,
cervixFirmness: "SOFT" as const,
cervixOpening: "OPEN" as const,
};
const input = buildDayLogInput(state, "2026-06-06");
expect(input.cervixPosition).toBe("HIGH");
expect(input.cervixFirmness).toBe("SOFT");
expect(input.cervixOpening).toBe("OPEN");
// A blank edit nulls every cervix sign (clear semantics).
const patch = buildDayLogPatch(blank());
expect(patch.cervixPosition).toBeNull();
expect(patch.cervixFirmness).toBeNull();
expect(patch.cervixOpening).toBeNull();
});
it("never marks an absent BBT reading disturbed", () => {
// A disturbed flag with no temperature is meaningless — it must reset.
const patch = buildDayLogPatch({ ...blank(), bbt: "", bbtDisturbed: true });
+38 -1
View File
@@ -17,7 +17,11 @@ import { Switch } from "@/components/ui/switch";
import { NativeSelect } from "@/components/ui/native-select";
import { Separator } from "@/components/ui/separator";
import { useTranslations } from "@/lib/i18n/context";
import type { CycleGoal, CycleProfileDTO } from "./types";
import type {
CycleGoal,
CycleProfileDTO,
SecondarySymptom,
} from "./types";
import { useUpdateCyclePrefs } from "./use-cycle";
/**
@@ -43,6 +47,8 @@ const GOALS: CycleGoal[] = [
"OFF",
];
const SECONDARY_SYMPTOMS: SecondarySymptom[] = ["MUCUS", "CERVIX"];
function numOrEmpty(v: number | null): string {
return v == null ? "" : String(v);
}
@@ -60,6 +66,9 @@ export function CycleSettings({ profile }: { profile: CycleProfileDTO }) {
profile.sensitiveCategoryEncryption,
);
const [discreet, setDiscreet] = useState(profile.discreetNotifications);
const [secondarySymptom, setSecondarySymptom] = useState<SecondarySymptom>(
profile.secondarySymptom,
);
const [cycleLen, setCycleLen] = useState(
numOrEmpty(profile.typicalCycleLength),
);
@@ -78,6 +87,7 @@ export function CycleSettings({ profile }: { profile: CycleProfileDTO }) {
async function handleSave() {
await update.mutateAsync({
goal,
secondarySymptom,
rawChartMode,
predictionEnabled,
sensitiveCategoryEncryption: encryption,
@@ -167,6 +177,33 @@ export function CycleSettings({ profile }: { profile: CycleProfileDTO }) {
<Separator />
{/* Advanced — symptothermal secondary symptom. The default is mucus;
the choice never forces itself on a casual user (progressive
disclosure: it sits here in the advanced cycle settings). */}
<div className="space-y-2">
<Label htmlFor="cycle-secondary-symptom">
{t("cycle.settings.secondarySymptomLabel")}
</Label>
<NativeSelect
id="cycle-secondary-symptom"
value={secondarySymptom}
onChange={(e) =>
setSecondarySymptom(e.target.value as SecondarySymptom)
}
>
{SECONDARY_SYMPTOMS.map((s) => (
<option key={s} value={s}>
{t(`cycle.settings.secondarySymptom.${s}`)}
</option>
))}
</NativeSelect>
<p className="text-muted-foreground text-sm">
{t("cycle.settings.secondarySymptomDescription")}
</p>
</div>
<Separator />
{/* Privacy toggles */}
<ToggleRow
id="cycle-encryption"
+112 -14
View File
@@ -50,6 +50,7 @@ import {
useCreateCustomSymptom,
useCustomSymptoms,
useCycleDayLog,
useCycleProfile,
useDeleteCustomSymptom,
useDeleteDayLog,
useEndPeriod,
@@ -63,6 +64,9 @@ import {
} from "./use-cycle";
import type {
CervicalMucus,
CervixFirmness,
CervixOpening,
CervixPosition,
ContraceptiveKind,
CycleDayLogInput,
CycleSymptomSelection,
@@ -98,6 +102,9 @@ const MUCUS_VALUES: CervicalMucus[] = [
"WATERY",
"EGG_WHITE",
];
const CERVIX_POSITION_VALUES: CervixPosition[] = ["LOW", "HIGH"];
const CERVIX_FIRMNESS_VALUES: CervixFirmness[] = ["FIRM", "SOFT"];
const CERVIX_OPENING_VALUES: CervixOpening[] = ["CLOSED", "OPEN"];
const TEST_RESULTS: HomeTestResult[] = [
"POSITIVE",
"NEGATIVE",
@@ -158,6 +165,9 @@ export interface DayLogFormState {
bbtDisturbed: boolean;
opk: OvulationTest | null;
mucus: CervicalMucus | null;
cervixPosition: CervixPosition | null;
cervixFirmness: CervixFirmness | null;
cervixOpening: CervixOpening | null;
intercourse: boolean;
protectedSex: boolean;
pregnancyTest: HomeTestResult | null;
@@ -195,6 +205,9 @@ export function buildDayLogPatch(s: DayLogFormState): CycleDayLogPatch {
temperatureExcluded: resolveBbt(s.bbt) != null ? s.bbtDisturbed : false,
ovulationTest: s.opk ?? null,
cervicalMucus: s.mucus ?? null,
cervixPosition: s.cervixPosition ?? null,
cervixFirmness: s.cervixFirmness ?? null,
cervixOpening: s.cervixOpening ?? null,
sexualActivity: s.intercourse,
protectedSex: s.intercourse ? s.protectedSex : null,
pregnancyTest: s.pregnancyTest ?? null,
@@ -223,6 +236,9 @@ export function buildDayLogInput(
: {}),
...(s.opk ? { ovulationTest: s.opk } : {}),
...(s.mucus ? { cervicalMucus: s.mucus } : {}),
...(s.cervixPosition ? { cervixPosition: s.cervixPosition } : {}),
...(s.cervixFirmness ? { cervixFirmness: s.cervixFirmness } : {}),
...(s.cervixOpening ? { cervixOpening: s.cervixOpening } : {}),
sexualActivity: s.intercourse,
protectedSex: s.intercourse ? s.protectedSex : null,
...(s.pregnancyTest ? { pregnancyTest: s.pregnancyTest } : {}),
@@ -274,6 +290,34 @@ function Chip({
);
}
/** One labelled row of cervix-sign chips (position / firmness / opening). */
function CervixRow<T extends string>({
label,
values,
current,
labelFor,
onToggle,
}: {
label: string;
values: readonly T[];
current: T | null;
labelFor: (v: T) => string;
onToggle: (v: T) => void;
}) {
return (
<div className="space-y-1.5">
<p className="text-muted-foreground text-xs font-medium">{label}</p>
<div className="flex flex-wrap gap-2">
{values.map((v) => (
<Chip key={v} active={current === v} onClick={() => onToggle(v)}>
{labelFor(v)}
</Chip>
))}
</div>
</div>
);
}
export function LogDaySheet({
open,
onOpenChange,
@@ -291,6 +335,11 @@ export function LogDaySheet({
const dayLog = useCycleDayLog(open ? date : null);
// The caller's custom symptoms, merged into the seeded chip grid.
const customSymptoms = useCustomSymptoms();
// Drives which symptothermal secondary sign the sheet offers — mucus (default)
// or the cervix pickers (progressive disclosure: cervix entry only appears
// when the user chose CERVIX in the advanced cycle settings).
const cycleProfile = useCycleProfile();
const showCervix = cycleProfile.data?.secondarySymptom === "CERVIX";
const [flow, setFlow] = useState<FlowLevel | null>(null);
const [intermenstrual, setIntermenstrual] = useState(false);
@@ -301,6 +350,13 @@ export function LogDaySheet({
const [bbtDisturbed, setBbtDisturbed] = useState(false);
const [opk, setOpk] = useState<OvulationTest | null>(null);
const [mucus, setMucus] = useState<CervicalMucus | null>(null);
const [cervixPosition, setCervixPosition] = useState<CervixPosition | null>(
null,
);
const [cervixFirmness, setCervixFirmness] = useState<CervixFirmness | null>(
null,
);
const [cervixOpening, setCervixOpening] = useState<CervixOpening | null>(null);
const [intercourse, setIntercourse] = useState(false);
const [protectedSex, setProtectedSex] = useState(false);
const [pregnancyTest, setPregnancyTest] = useState<HomeTestResult | null>(
@@ -334,6 +390,9 @@ export function LogDaySheet({
setBbtDisturbed(dto?.temperatureExcluded ?? false);
setOpk((dto?.ovulationTest ?? null) as OvulationTest | null);
setMucus((dto?.cervicalMucus ?? null) as CervicalMucus | null);
setCervixPosition((dto?.cervixPosition ?? null) as CervixPosition | null);
setCervixFirmness((dto?.cervixFirmness ?? null) as CervixFirmness | null);
setCervixOpening((dto?.cervixOpening ?? null) as CervixOpening | null);
setIntercourse(dto?.sexualActivity ?? false);
setProtectedSex(dto?.protectedSex ?? false);
setPregnancyTest(dto?.pregnancyTest ?? null);
@@ -370,6 +429,9 @@ export function LogDaySheet({
bbtDisturbed,
opk,
mucus,
cervixPosition,
cervixFirmness,
cervixOpening,
intercourse,
protectedSex,
pregnancyTest,
@@ -644,20 +706,56 @@ export function LogDaySheet({
</div>
</Field>
{/* Cervical mucus */}
<Field label={t("cycle.sheet.mucus")}>
<div className="flex flex-wrap gap-2">
{MUCUS_VALUES.map((v) => (
<Chip
key={v}
active={mucus === v}
onClick={() => setMucus((cur) => (cur === v ? null : v))}
>
{t(`cycle.mucus.${v}`)}
</Chip>
))}
</div>
</Field>
{/* Symptothermal secondary symptom: cervical mucus (default) OR the
cervix observation, per the user's advanced-settings choice. Only one
of the two is offered so the log sheet never overwhelms. */}
{showCervix ? (
<Field label={t("cycle.sheet.cervix")}>
<div className="space-y-3">
<CervixRow
label={t("cycle.sheet.cervixPosition")}
values={CERVIX_POSITION_VALUES}
current={cervixPosition}
labelFor={(v) => t(`cycle.cervixPosition.${v}`)}
onToggle={(v) =>
setCervixPosition((cur) => (cur === v ? null : v))
}
/>
<CervixRow
label={t("cycle.sheet.cervixFirmness")}
values={CERVIX_FIRMNESS_VALUES}
current={cervixFirmness}
labelFor={(v) => t(`cycle.cervixFirmness.${v}`)}
onToggle={(v) =>
setCervixFirmness((cur) => (cur === v ? null : v))
}
/>
<CervixRow
label={t("cycle.sheet.cervixOpening")}
values={CERVIX_OPENING_VALUES}
current={cervixOpening}
labelFor={(v) => t(`cycle.cervixOpening.${v}`)}
onToggle={(v) =>
setCervixOpening((cur) => (cur === v ? null : v))
}
/>
</div>
</Field>
) : (
<Field label={t("cycle.sheet.mucus")}>
<div className="flex flex-wrap gap-2">
{MUCUS_VALUES.map((v) => (
<Chip
key={v}
active={mucus === v}
onClick={() => setMucus((cur) => (cur === v ? null : v))}
>
{t(`cycle.mucus.${v}`)}
</Chip>
))}
</div>
</Field>
)}
{/* Intercourse + protection */}
<Field label={t("cycle.sheet.intercourse")}>
+15
View File
@@ -101,9 +101,18 @@ export interface CycleHistoryResponse {
};
}
/** Symptothermal secondary symptom — mucus (default) or cervix observation. */
export type SecondarySymptom = "MUCUS" | "CERVIX";
/** The three Sensiplan cervix signs. */
export type CervixPosition = "LOW" | "HIGH";
export type CervixFirmness = "FIRM" | "SOFT";
export type CervixOpening = "CLOSED" | "OPEN";
export interface CycleProfileDTO {
goal: CycleGoal;
cycleTrackingEnabled: boolean;
secondarySymptom: SecondarySymptom;
rawChartMode: boolean;
predictionEnabled: boolean;
discreetNotifications: boolean;
@@ -141,6 +150,9 @@ export interface CycleDayLogInput {
temperatureExcluded?: boolean;
ovulationTest?: OvulationTest;
cervicalMucus?: CervicalMucus;
cervixPosition?: CervixPosition | null;
cervixFirmness?: CervixFirmness | null;
cervixOpening?: CervixOpening | null;
sexualActivity?: boolean;
protectedSex?: boolean | null;
pregnancyTest?: HomeTestResult;
@@ -163,6 +175,9 @@ export interface CycleDayLogDTO {
temperatureExcluded: boolean;
ovulationTest: OvulationTest | null;
cervicalMucus: CervicalMucus | null;
cervixPosition: CervixPosition | null;
cervixFirmness: CervixFirmness | null;
cervixOpening: CervixOpening | null;
sexualActivity: boolean;
protectedSex: boolean | null;
pregnancyTest: HomeTestResult | null;
+7
View File
@@ -29,6 +29,9 @@ import {
import type {
CalendarResponse,
CervicalMucus,
CervixFirmness,
CervixOpening,
CervixPosition,
ContraceptiveKind,
CycleDayLogDTO,
CycleDayLogInput,
@@ -240,6 +243,9 @@ export interface CycleDayLogPatch {
temperatureExcluded?: boolean;
ovulationTest?: OvulationTest | null;
cervicalMucus?: CervicalMucus | null;
cervixPosition?: CervixPosition | null;
cervixFirmness?: CervixFirmness | null;
cervixOpening?: CervixOpening | null;
sexualActivity?: boolean;
protectedSex?: boolean | null;
pregnancyTest?: HomeTestResult | null;
@@ -317,6 +323,7 @@ export function useDeleteDayLog() {
export interface CyclePrefsPatch {
enabled?: boolean;
goal?: CycleProfileDTO["goal"];
secondarySymptom?: CycleProfileDTO["secondarySymptom"];
rawChartMode?: boolean;
predictionEnabled?: boolean;
discreetNotifications?: boolean;