diff --git a/src/app/features/room/ScheduleMessageModal.tsx b/src/app/features/room/ScheduleMessageModal.tsx
index 0bdb872b8..2ad8fa487 100644
--- a/src/app/features/room/ScheduleMessageModal.tsx
+++ b/src/app/features/room/ScheduleMessageModal.tsx
@@ -20,7 +20,12 @@ import { IContent } from 'matrix-js-sdk';
import { useTimestampFormatter } from '../../hooks/useTimestampFormatter';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { stopPropagation } from '../../utils/keyboard';
-import { scheduleMessage } from '../../utils/scheduledMessages';
+import {
+ describeScheduleError,
+ MAX_SCHEDULE_AHEAD_MS,
+ scheduleMessage,
+ SCHEDULE_TOO_FAR_TEXT,
+} from '../../utils/scheduledMessages';
import { useModalStyle } from '../../hooks/useModalStyle';
import {
toLocalDate,
@@ -121,7 +126,13 @@ export function ScheduleMessageModal({
return;
}
const diffMs = sendAt.getTime() - Date.now();
- if (diffMs < 60_000) {
+ // [Gitea #275] Say so as soon as a too-late time is picked, not on submit.
+ const tooFar = diffMs > MAX_SCHEDULE_AHEAD_MS;
+ setError((e) => {
+ if (tooFar) return SCHEDULE_TOO_FAR_TEXT;
+ return e === SCHEDULE_TOO_FAR_TEXT ? null : e;
+ });
+ if (diffMs < 60_000 || tooFar) {
setPreview(null);
return;
}
@@ -149,6 +160,10 @@ export function ScheduleMessageModal({
setError('Scheduled time must be at least 1 minute in the future.');
return;
}
+ if (diffMs > MAX_SCHEDULE_AHEAD_MS) {
+ setError(SCHEDULE_TOO_FAR_TEXT);
+ return;
+ }
if (!messageText.trim()) {
setError('Please enter a message to schedule.');
return;
@@ -162,7 +177,7 @@ export function ScheduleMessageModal({
onScheduled(delayId, sendAt.getTime(), content);
onClose();
} catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to schedule message.');
+ setError(describeScheduleError(err));
setSubmitting(false);
}
};
@@ -247,6 +262,8 @@ export function ScheduleMessageModal({
setDateValue(e.target.value)}
style={pickerInputStyle(color, config)}
@@ -294,7 +311,8 @@ export function ScheduleMessageModal({
) : (
- (dateValue || timeValue) && (
+ (dateValue || timeValue) &&
+ error !== SCHEDULE_TOO_FAR_TEXT && (
Must be at least 1 minute in the future
diff --git a/src/app/utils/scheduledMessages.test.ts b/src/app/utils/scheduledMessages.test.ts
index c3328fd5f..45c2e7fb3 100644
--- a/src/app/utils/scheduledMessages.test.ts
+++ b/src/app/utils/scheduledMessages.test.ts
@@ -179,3 +179,15 @@ test('groupScheduledByRoom: groups and sorts by sendAt', () => {
);
assert.equal(g.get('!2')?.length, 1);
});
+
+test('[#275] the server limit maps to friendly text; other errors keep theirs', async () => {
+ const { describeScheduleError, SCHEDULE_TOO_FAR_TEXT, MAX_SCHEDULE_AHEAD_MS } =
+ await import('./scheduledMessages');
+ assert.equal(MAX_SCHEDULE_AHEAD_MS, 86_400_000);
+ const tooLarge = Object.assign(new Error('The requested delay (172800000ms) exceeds…'), {
+ errcode: 'ORG.MATRIX.MSC4140_DELAY_TOO_LARGE',
+ });
+ assert.equal(describeScheduleError(tooLarge), SCHEDULE_TOO_FAR_TEXT);
+ assert.equal(describeScheduleError(new Error('Boom')), 'Boom');
+ assert.equal(describeScheduleError('nope'), 'Failed to schedule message.');
+});
diff --git a/src/app/utils/scheduledMessages.ts b/src/app/utils/scheduledMessages.ts
index a8acde312..0b76e1ed9 100644
--- a/src/app/utils/scheduledMessages.ts
+++ b/src/app/utils/scheduledMessages.ts
@@ -1,6 +1,22 @@
import { IContent, MatrixClient, Method } from 'matrix-js-sdk';
import type { ScheduledMessage } from '../state/scheduledMessages';
+/**
+ * [Gitea #275] Production Synapse caps delayed events at
+ * `max_event_delay_duration: 24h`; a later time is rejected with
+ * ORG.MATRIX.MSC4140_DELAY_TOO_LARGE. The dialog enforces the same limit and
+ * the server's error maps to the same text, in case the limit changes.
+ */
+export const MAX_SCHEDULE_AHEAD_MS = 24 * 60 * 60 * 1000;
+export const SCHEDULE_TOO_FAR_TEXT = 'You can schedule up to 24 hours ahead.';
+
+/** A user-facing sentence for a failed schedule. */
+export const describeScheduleError = (err: unknown): string => {
+ const errcode = (err as { errcode?: unknown } | null)?.errcode;
+ if (errcode === 'ORG.MATRIX.MSC4140_DELAY_TOO_LARGE') return SCHEDULE_TOO_FAR_TEXT;
+ return err instanceof Error ? err.message : 'Failed to schedule message.';
+};
+
/**
* Schedule a message via MSC4140 (delayed messages).
* Synapse implementation: pass org.matrix.msc4140.delay on the standard