feat(core): add a two-step confirm page to create new journal (#13240)
close AF-2750; <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced a new workspace journals page with date-based navigation, placeholder UI, and the ability to create daily journals directly from the page. * Added a "Today" button for quick navigation to the current day's journal when viewing other dates. * **Improvements** * Enhanced the journal document title display with improved date formatting and flexible styling. * Expanded the active state for the journal sidebar button to cover all journal-related routes. * Updated journal navigation to open existing entries directly or navigate to filtered journal listings. * **Bug Fixes** * Improved date handling and navigation logic for journal entries to ensure accurate redirection and creation flows. * **Style** * Added new styles for the workspace journals page, including headers, placeholders, and buttons. * **Localization** * Added English translations for journal placeholder text and create journal prompts. * **Tests** * Added confirmation steps in journal creation flows to improve test reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -9,20 +9,40 @@ import * as styles from './styles.css';
|
||||
export const BlocksuiteEditorJournalDocTitle = ({ page }: { page: Store }) => {
|
||||
const journalService = useService(JournalService);
|
||||
const journalDateStr = useLiveData(journalService.journalDate$(page.id));
|
||||
const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
|
||||
const isTodayJournal = useLiveData(journalService.journalToday$(page.id));
|
||||
const localizedJournalDate = i18nTime(journalDateStr, {
|
||||
|
||||
return <BlocksuiteEditorJournalDocTitleUI date={journalDateStr} />;
|
||||
};
|
||||
|
||||
export const BlocksuiteEditorJournalDocTitleUI = ({
|
||||
date: dateStr,
|
||||
overrideClassName,
|
||||
}: {
|
||||
date?: string;
|
||||
/**
|
||||
* The `doc-title-container` class style is defined in editor,
|
||||
* which means if we use this component outside editor, the style will not work,
|
||||
* so we provide a className to override
|
||||
*/
|
||||
overrideClassName?: string;
|
||||
}) => {
|
||||
const localizedJournalDate = i18nTime(dateStr, {
|
||||
absolute: { accuracy: 'day' },
|
||||
});
|
||||
const t = useI18n();
|
||||
|
||||
// TODO(catsjuice): i18n
|
||||
const day = journalDate?.format('dddd') ?? null;
|
||||
const today = dayjs();
|
||||
const date = dayjs(dateStr);
|
||||
const day = dayjs(date).format('dddd') ?? null;
|
||||
const isToday = date.isSame(today, 'day');
|
||||
|
||||
return (
|
||||
<div className="doc-title-container" data-testid="journal-title">
|
||||
<div
|
||||
className={overrideClassName ?? 'doc-title-container'}
|
||||
data-testid="journal-title"
|
||||
>
|
||||
<span data-testid="date">{localizedJournalDate}</span>
|
||||
{isTodayJournal ? (
|
||||
{isToday ? (
|
||||
<span className={styles.titleTodayTag} data-testid="date-today-label">
|
||||
{t['com.affine.today']()}
|
||||
</span>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import type { WeekDatePickerHandle } from '@affine/component';
|
||||
import { WeekDatePicker } from '@affine/component';
|
||||
import { useJournalRouteHelper } from '@affine/core/components/hooks/use-journal';
|
||||
import { JournalService } from '@affine/core/modules/journal';
|
||||
import {
|
||||
JOURNAL_DATE_FORMAT,
|
||||
JournalService,
|
||||
} from '@affine/core/modules/journal';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import type { Store } from '@blocksuite/affine/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import dayjs from 'dayjs';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
export interface JournalWeekDatePickerProps {
|
||||
page: Store;
|
||||
@@ -17,17 +20,29 @@ export const JournalWeekDatePicker = ({ page }: JournalWeekDatePickerProps) => {
|
||||
const journalService = useService(JournalService);
|
||||
const journalDateStr = useLiveData(journalService.journalDate$(page.id));
|
||||
const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
|
||||
const { openJournal } = useJournalRouteHelper();
|
||||
const [date, setDate] = useState(
|
||||
(journalDate ?? dayjs()).format('YYYY-MM-DD')
|
||||
(journalDate ?? dayjs()).format(JOURNAL_DATE_FORMAT)
|
||||
);
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
|
||||
useEffect(() => {
|
||||
if (!journalDate) return;
|
||||
setDate(journalDate.format('YYYY-MM-DD'));
|
||||
setDate(journalDate.format(JOURNAL_DATE_FORMAT));
|
||||
handleRef.current?.setCursor?.(journalDate);
|
||||
}, [journalDate]);
|
||||
|
||||
const openJournal = useCallback(
|
||||
(date: string) => {
|
||||
const docs = journalService.journalsByDate$(date).value;
|
||||
if (docs.length > 0) {
|
||||
workbench.openDoc(docs[0].id, { at: 'active' });
|
||||
} else {
|
||||
workbench.open(`/journals?date=${date}`, { at: 'active' });
|
||||
}
|
||||
},
|
||||
[journalService, workbench]
|
||||
);
|
||||
|
||||
return (
|
||||
<WeekDatePicker
|
||||
data-testid="journal-week-picker"
|
||||
|
||||
Reference in New Issue
Block a user