mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-23 19:49:56 +01:00
Merge pull request #7303 from 01zulfi/web/reminder-dialog-improvements
web: reminder dialogs improvements
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -96,7 +96,8 @@ export const ReminderPreviewDialog = DialogManager.register(
|
||||
sx={{
|
||||
alignItems: "center",
|
||||
my: 1,
|
||||
gap: 1
|
||||
gap: 1,
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{SNOOZE_TIMES.map((time) => (
|
||||
|
||||
Reference in New Issue
Block a user