Merge pull request #7303 from 01zulfi/web/reminder-dialog-improvements

web: reminder dialogs improvements
This commit is contained in:
Abdullah Atta
2026-02-02 12:30:40 +05:00
committed by GitHub
8 changed files with 170 additions and 32 deletions

View File

@@ -252,14 +252,16 @@ const NoteItem = ({
{reminder ? (
<ReminderTime
reminder={reminder}
disabled
color={color?.colorCode}
textStyle={{
fontSize: AppFontSize.xxxs
fontSize: AppFontSize.xxs
}}
iconSize={AppFontSize.xxxs}
short
iconSize={AppFontSize.xxs}
style={{
height: "auto"
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start"
}}
/>
) : null}

View File

@@ -41,7 +41,9 @@ export const ReminderTime = ({
} & ButtonProps) => {
const { colors } = useThemeColors();
const reminder = props.reminder;
const time = !reminder ? undefined : getFormattedReminderTime(reminder);
const time = !reminder
? undefined
: getFormattedReminderTime(reminder, props.short || false);
const isTodayOrTomorrow =
(time?.includes("Today") || time?.includes("Tomorrow")) &&
!time?.includes("Last");

View File

@@ -39,7 +39,7 @@ import Input from "../../components/ui/input";
import { ReminderTime } from "../../components/ui/reminder-time";
import Paragraph from "../../components/ui/typography/paragraph";
import { DDS } from "../../services/device-detection";
import { ToastManager } from "../../services/event-manager";
import { eSendEvent, ToastManager } from "../../services/event-manager";
import Navigation, { NavigationProps } from "../../services/navigation";
import Notifications from "../../services/notifications";
import SettingsService from "../../services/settings";
@@ -47,9 +47,18 @@ import { useRelationStore } from "../../stores/use-relation-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { getFormattedDate, useIsFeatureAvailable } from "@notesnook/common";
import {
getFormattedDate,
useIsFeatureAvailable,
usePromise
} from "@notesnook/common";
import PaywallSheet from "../../components/sheets/paywall";
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
import { Pressable } from "../../components/ui/pressable";
import { TimeSince } from "../../components/ui/time-since";
import Heading from "../../components/ui/typography/heading";
import { eOnLoadNote } from "../../utils/events";
import { fluidTabsRef } from "../../utils/global-refs";
const ReminderModes =
Platform.OS === "ios"
@@ -114,6 +123,15 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
const titleRef = useRef<TextInput>(null);
const descriptionRef = useRef<TextInput>(null);
const timer = useRef<NodeJS.Timeout>(undefined);
const referencedNotes = usePromise(
() =>
reminder?.id
? db.relations
.to({ id: reminder.id, type: "reminder" }, "note")
.resolve()
: null,
[reminder?.id]
);
const showDatePicker = () => {
setDatePickerVisibility(true);
@@ -237,6 +255,9 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
marginBottom: DDS.isTab ? 25 : undefined,
paddingHorizontal: DefaultAppStyles.GAP
}}
contentContainerStyle={{
gap: DefaultAppStyles.GAP_VERTICAL
}}
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
>
@@ -271,15 +292,11 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
paddingVertical: DefaultAppStyles.GAP_VERTICAL
}}
height={80}
wrapperStyle={{
marginBottom: DefaultAppStyles.GAP_VERTICAL
}}
/>
<ScrollView
style={{
flexDirection: "row",
marginBottom: DefaultAppStyles.GAP_VERTICAL
flexDirection: "row"
}}
horizontal
>
@@ -335,8 +352,7 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
style={{
backgroundColor: colors.secondary.background,
padding: DefaultAppStyles.GAP,
borderRadius: defaultBorderRadius,
marginBottom: DefaultAppStyles.GAP_VERTICAL
borderRadius: defaultBorderRadius
}}
>
<View
@@ -454,7 +470,6 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
width: "100%",
flexDirection: "column",
justifyContent: "center",
marginBottom: DefaultAppStyles.GAP_VERTICAL,
alignItems: "center"
}}
>
@@ -513,10 +528,8 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
style={{
borderRadius: defaultBorderRadius,
flexDirection: "row",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
alignItems: "center",
justifyContent: "flex-start",
marginBottom: DefaultAppStyles.GAP_VERTICAL
justifyContent: "flex-start"
}}
>
<>
@@ -552,22 +565,10 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
</View>
)}
<ReminderTime
reminder={reminder}
style={{
width: "100%",
justifyContent: "flex-start",
borderWidth: 0,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
alignSelf: "flex-start"
}}
/>
{reminderMode === ReminderModes.Permanent ? null : (
<ScrollView
style={{
flexDirection: "row",
marginTop: DefaultAppStyles.GAP_VERTICAL,
height: 50
}}
horizontal
@@ -612,6 +613,60 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
))}
</ScrollView>
)}
<ReminderTime
reminder={reminder}
style={{
width: "100%",
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
alignSelf: "flex-start"
}}
/>
{referencedNotes &&
referencedNotes.status === "fulfilled" &&
referencedNotes.value !== null &&
referencedNotes.value?.length > 0 ? (
<View
style={{
gap: DefaultAppStyles.GAP_VERTICAL
}}
>
<Heading size={AppFontSize.md}>{strings.referencedIn()}</Heading>
{referencedNotes.value.map((item) => (
<Pressable
style={{
justifyContent: "space-between",
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
}}
onPress={() => {
Navigation.navigate("FluidPanelsView");
fluidTabsRef.current?.goToPage("editor");
eSendEvent(eOnLoadNote, {
item: item
});
}}
type="secondary"
>
<Paragraph>{item.title}</Paragraph>
<TimeSince
style={{
fontSize: AppFontSize.xxs,
color: colors.secondary.paragraph,
marginRight: 6
}}
time={item.dateEdited}
updateFrequency={
Date.now() - item.dateEdited < 60000 ? 2000 : 60000
}
/>
</Pressable>
))}
</View>
) : null}
</ScrollView>
</KeyboardViewIOS>
</SafeAreaView>

View File

@@ -27,10 +27,12 @@ import {
fillColorDialog,
fillNotebookDialog,
fillPasswordDialog,
fillReminderDialog,
iterateList
} from "./utils";
import { SessionHistoryItemModel } from "./session-history-item-model";
import dayjs from "dayjs";
import { Reminder } from "@notesnook/core";
abstract class BaseProperties {
protected readonly page: Page;
@@ -388,6 +390,12 @@ export class NoteContextMenuModel extends BaseProperties {
await confirmDialog(dialog);
}
async addReminder(reminder: Partial<Reminder>) {
await this.open();
await this.menu.clickOnItem("remind-me");
await fillReminderDialog(this.page, reminder);
}
async open() {
await this.menu.open(this.noteLocator);
}

View File

@@ -62,4 +62,9 @@ export class ReminderItemModel extends BaseItemModel {
await this.contextMenu.open(this.locator);
await this.contextMenu.clickOnItem("toggle");
}
async open() {
await this.contextMenu.open(this.locator);
await this.contextMenu.clickOnItem("edit");
}
}

View File

@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Reminder } from "@notesnook/core";
import { test, expect } from "@playwright/test";
import { AppModel } from "./models/app.model";
import { getTestId } from "./utils";
const ONE_TIME_REMINDER: Partial<Reminder> = {
title: "Test reminder 1",
@@ -197,3 +198,26 @@ test("editing a weekly recurring reminder should not revert it to daily", async
expect(await reminder?.getRecurringMode()).toBe("Weekly");
expect(await reminder?.getDescription()).toBe("An edited reminder");
});
test("adding a reminder via note context menu should show reference in edit dialog", async ({
page
}) => {
const app = new AppModel(page);
await app.goto();
const notes = await app.goToNotes();
const note = await notes.createNote({
title: "Test note",
content: "I am a note"
});
await note?.contextMenu.addReminder(ONE_TIME_REMINDER);
const reminders = await app.goToReminders();
const reminder = await reminders.findReminder({
title: ONE_TIME_REMINDER.title
});
await reminder?.open();
const noteReferences = page.locator(getTestId("reminder-note-references"));
await noteReferences.waitFor({ state: "visible" });
expect(noteReferences.getByText("Test note")).toBeVisible();
});

View File

@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import NoteItem from "../components/note";
import Dialog from "../components/dialog";
import Field from "../components/field";
import { Box, Button, Flex, Label, Radio, Text } from "@theme-ui/components";
@@ -32,13 +33,18 @@ import { usePersistentState } from "../hooks/use-persistent-state";
import { DayPicker } from "../components/day-picker";
import { PopupPresenter } from "@notesnook/ui";
import { useStore as useThemeStore } from "../stores/theme-store";
import { getFormattedDate, useIsFeatureAvailable } from "@notesnook/common";
import {
getFormattedDate,
useIsFeatureAvailable,
usePromise
} from "@notesnook/common";
import { MONTHS_FULL, getTimeFormat } from "@notesnook/core";
import { Note, Reminder } from "@notesnook/core";
import { BaseDialogProps, DialogManager } from "../common/dialog-manager";
import { strings } from "@notesnook/intl";
import { checkFeature } from "../common";
import { setTimeOnly, setDateOnly } from "../utils/date-time";
import Skeleton from "react-loading-skeleton";
dayjs.extend(customParseFormat);
@@ -148,6 +154,15 @@ export const AddReminderDialog = DialogManager.register(
const theme = useThemeStore((store) => store.colorScheme);
const dateInputRef = useRef<HTMLInputElement>(null);
const repeatModeAvailability = useIsFeatureAvailable("recurringReminders");
const referencedNotes = usePromise(
() =>
reminder?.id
? db.relations
.to({ id: reminder.id, type: "reminder" }, "note")
.resolve()
: null,
[reminder?.id]
);
const repeatsDaily =
(selectedDays.length === 7 && recurringMode === RecurringModes.WEEK) ||
@@ -512,6 +527,32 @@ export const AddReminderDialog = DialogManager.register(
{strings.reminderStarts(date.format(db.settings.getDateFormat()), date.format(timeFormat()))}
</Text>
)}
{reminder ? (
referencedNotes && referencedNotes.status === "fulfilled" ? (
referencedNotes.value !== null &&
referencedNotes.value.length > 0 && (
<Flex
data-test-id="reminder-note-references"
sx={{ my: 2, gap: 1, flexDirection: "column" }}
>
<Text variant="body">
{strings.note()} {strings.references()}:
</Text>
{referencedNotes.value.map((item) => (
<NoteItem
key={item.id}
item={item}
date={item.dateCreated}
compact
/>
))}
</Flex>
)
) : (
<Skeleton count={1} />
)
) : null}
</Dialog>
);
},

View File

@@ -96,7 +96,8 @@ export const ReminderPreviewDialog = DialogManager.register(
sx={{
alignItems: "center",
my: 1,
gap: 1
gap: 1,
flexWrap: "wrap"
}}
>
{SNOOZE_TIMES.map((time) => (