Track dirty state to skip discard prompt for unchanged drafts
When a draft is loaded and the user hasn't made any changes, closing the composer should not show the discard prompt since nothing would be lost. - Add isDirty field to ComposerState - Set isDirty: true on all content-modifying actions - Set isDirty: false on restore_from_draft, clear, and initial state - Update onPressCancel to only show prompt if no draft or isDirty Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -413,21 +413,31 @@ export const ComposePost = ({
|
|||||||
const onPressCancel = useCallback(() => {
|
const onPressCancel = useCallback(() => {
|
||||||
if (textInput.current?.maybeClosePopup()) {
|
if (textInput.current?.maybeClosePopup()) {
|
||||||
return
|
return
|
||||||
} else if (
|
}
|
||||||
thread.posts.some(
|
|
||||||
post =>
|
const hasContent = thread.posts.some(
|
||||||
post.shortenedGraphemeLength > 0 ||
|
post =>
|
||||||
post.embed.media ||
|
post.shortenedGraphemeLength > 0 || post.embed.media || post.embed.link,
|
||||||
post.embed.link,
|
)
|
||||||
)
|
|
||||||
) {
|
// Show discard prompt if there's content AND either:
|
||||||
|
// - No draft is loaded (new composition)
|
||||||
|
// - Draft is loaded but has been modified
|
||||||
|
if (hasContent && (!composerState.draftId || composerState.isDirty)) {
|
||||||
closeAllDialogs()
|
closeAllDialogs()
|
||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
discardPromptControl.open()
|
discardPromptControl.open()
|
||||||
} else {
|
} else {
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
}, [thread, closeAllDialogs, discardPromptControl, onClose])
|
}, [
|
||||||
|
thread,
|
||||||
|
composerState.draftId,
|
||||||
|
composerState.isDirty,
|
||||||
|
closeAllDialogs,
|
||||||
|
discardPromptControl,
|
||||||
|
onClose,
|
||||||
|
])
|
||||||
|
|
||||||
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ export type ComposerState = {
|
|||||||
mutableNeedsFocusActive: boolean
|
mutableNeedsFocusActive: boolean
|
||||||
/** ID of the draft being edited, if any. Used to update existing draft on save. */
|
/** ID of the draft being edited, if any. Used to update existing draft on save. */
|
||||||
draftId?: string
|
draftId?: string
|
||||||
|
/** Whether the composer has been modified since loading a draft. */
|
||||||
|
isDirty: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ComposerAction =
|
export type ComposerAction =
|
||||||
@@ -145,6 +147,7 @@ export function composerReducer(
|
|||||||
case 'update_postgate': {
|
case 'update_postgate': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
isDirty: true,
|
||||||
thread: {
|
thread: {
|
||||||
...state.thread,
|
...state.thread,
|
||||||
postgate: action.postgate,
|
postgate: action.postgate,
|
||||||
@@ -154,6 +157,7 @@ export function composerReducer(
|
|||||||
case 'update_threadgate': {
|
case 'update_threadgate': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
isDirty: true,
|
||||||
thread: {
|
thread: {
|
||||||
...state.thread,
|
...state.thread,
|
||||||
threadgate: action.threadgate,
|
threadgate: action.threadgate,
|
||||||
@@ -174,6 +178,7 @@ export function composerReducer(
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
isDirty: true,
|
||||||
thread: {
|
thread: {
|
||||||
...state.thread,
|
...state.thread,
|
||||||
posts: nextPosts,
|
posts: nextPosts,
|
||||||
@@ -196,6 +201,7 @@ export function composerReducer(
|
|||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
isDirty: true,
|
||||||
thread: {
|
thread: {
|
||||||
...state.thread,
|
...state.thread,
|
||||||
posts: nextPosts,
|
posts: nextPosts,
|
||||||
@@ -221,6 +227,7 @@ export function composerReducer(
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
isDirty: true,
|
||||||
activePostIndex: nextActivePostIndex,
|
activePostIndex: nextActivePostIndex,
|
||||||
mutableNeedsFocusActive: true,
|
mutableNeedsFocusActive: true,
|
||||||
thread: {
|
thread: {
|
||||||
@@ -305,6 +312,7 @@ export function composerReducer(
|
|||||||
activePostIndex: 0,
|
activePostIndex: 0,
|
||||||
mutableNeedsFocusActive: true,
|
mutableNeedsFocusActive: true,
|
||||||
draftId: draft.id,
|
draftId: draft.id,
|
||||||
|
isDirty: false,
|
||||||
thread: {
|
thread: {
|
||||||
posts,
|
posts,
|
||||||
postgate: draft.postgate || state.thread.postgate,
|
postgate: draft.postgate || state.thread.postgate,
|
||||||
@@ -317,6 +325,7 @@ export function composerReducer(
|
|||||||
activePostIndex: 0,
|
activePostIndex: 0,
|
||||||
mutableNeedsFocusActive: true,
|
mutableNeedsFocusActive: true,
|
||||||
draftId: undefined,
|
draftId: undefined,
|
||||||
|
isDirty: false,
|
||||||
thread: {
|
thread: {
|
||||||
posts: [
|
posts: [
|
||||||
{
|
{
|
||||||
@@ -699,6 +708,7 @@ export function createComposerState({
|
|||||||
return {
|
return {
|
||||||
activePostIndex: 0,
|
activePostIndex: 0,
|
||||||
mutableNeedsFocusActive: false,
|
mutableNeedsFocusActive: false,
|
||||||
|
isDirty: false,
|
||||||
thread: {
|
thread: {
|
||||||
posts: [
|
posts: [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user