Skip to content

Commit 4f15f19

Browse files
committed
feat: saving indicator while update title request is in progress
1 parent fa7c5ad commit 4f15f19

File tree

7 files changed

+41
-25
lines changed

7 files changed

+41
-25
lines changed

components/EditorNavbar/index.tsx

+1-9
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,15 @@ import AccountActions from "components/AccountActions";
1717
import StartPresentationModeButton from "components/StartPresentationModeButton";
1818
import PublishSettingsModal from "components/PublishSettingsModal";
1919
import { useStore } from "lib/stores/presentation";
20-
import { updateRemoteForId } from "lib/updateRemoteTitle";
2120

2221
export interface EditorNavbarProps {}
2322

2423
export const EditorNavbar: FC<EditorNavbarProps> = () => {
2524
const { isOpen, onClose, onOpen } = useDisclosure();
26-
const pid = useStore((state) => state.presentation.id);
2725
const isSaving = useStore((state) => state.isSaving);
2826
const title = useStore((state) => state.presentation.title);
2927

30-
const updateRemoteTitle = updateRemoteForId(pid);
31-
const updateLocalTitle = useStore((store) => store.updateLocalTitle);
32-
33-
const updateTitle = async (newTitle: string) => {
34-
updateLocalTitle(newTitle);
35-
updateRemoteTitle(newTitle.trim() || "Untitled");
36-
};
28+
const updateTitle = useStore((store) => store.updateTitle);
3729

3830
return (
3931
<>

lib/stores/presentation/index.ts

+28-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import create from "zustand";
22
import Slide from "model/slide";
33
import Presentation from "model/interfaces/presentation";
44
import { updateSlideRemote } from "./updateSlideRemote";
5+
import { updateRemoteForId } from "./updateRemoteTitle";
56

67
type MapToPartial<T> = (value: T) => Partial<T>;
78

@@ -12,7 +13,7 @@ type State = {
1213
"slides" | "isPublished" | "pubmeta" | "title"
1314
> &
1415
Partial<Pick<Presentation, "id">>;
15-
lastSlideUpdatePromise: Promise<void> | null;
16+
lastSlideUpdatePromise: Promise<any> | null;
1617
isSaving: boolean;
1718
isPresentationMode: boolean;
1819
};
@@ -28,7 +29,7 @@ type Actions = {
2829
setPresentation: (presentation: Presentation) => void;
2930
startPresentationMode: () => void;
3031
stopPresentationMode: () => void;
31-
updateLocalTitle: (newTitle: string) => void;
32+
updateTitle: (newTitle: string) => void;
3233
};
3334

3435
const defaultSlideValue: Slide = {
@@ -78,7 +79,7 @@ export const useStore = create<State & Actions>((set, get) => ({
7879
updateSlideRemote(slide, pid, idx, (promise) => {
7980
set({ lastSlideUpdatePromise: promise });
8081

81-
promise.then(() => {
82+
promise.finally(() => {
8283
const { lastSlideUpdatePromise } = get();
8384
if (lastSlideUpdatePromise === promise) {
8485
set({ isSaving: false });
@@ -131,9 +132,31 @@ export const useStore = create<State & Actions>((set, get) => ({
131132
stopPresentationMode: () => {
132133
set({ isPresentationMode: false });
133134
},
134-
updateLocalTitle: (newTitle: string) => {
135+
updateTitle: (newTitle: string) => {
135136
const { presentation } = get();
136-
set({ presentation: { ...presentation, title: newTitle } });
137+
138+
if (!newTitle || newTitle?.trim() === "") {
139+
return;
140+
}
141+
142+
updateRemoteForId(presentation.id)(newTitle, (promise) => {
143+
const { lastSlideUpdatePromise } = get();
144+
const combinedPromise = Promise.allSettled(
145+
[promise, lastSlideUpdatePromise].filter(Boolean)
146+
);
147+
148+
combinedPromise.finally(() => {
149+
const { lastSlideUpdatePromise } = get();
150+
if (lastSlideUpdatePromise === combinedPromise) {
151+
set({ isSaving: false, lastSlideUpdatePromise: null });
152+
}
153+
});
154+
155+
// @TODO change name to generalize.
156+
set({ lastSlideUpdatePromise: combinedPromise });
157+
});
158+
159+
set({ presentation: { ...presentation, title: newTitle }, isSaving: true });
137160
},
138161
}));
139162

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import axios from "axios";
2+
import debounce from "debounce";
3+
4+
export const updateRemoteForId = (pid: string) =>
5+
debounce((newTitle: string, callback: (promise: Promise<any>) => void) => {
6+
// TODO handle error.
7+
const promise = axios.patch(`/api/p/${pid}/title`, { title: newTitle });
8+
callback(promise);
9+
}, 500);

lib/updateRemoteTitle.ts

-8
This file was deleted.

pages/app/[pid].tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { getDb } from "lib/db/getDb";
1919
import { Slide } from "model/slide";
2020
import { useStore } from "lib/stores/presentation";
21-
import { keyListeners } from "lib/setupKeyListeners";
21+
import { keyListeners } from "@lib/setupKeyListeners";
2222

2323
interface EditorPageProps {
2424
presentation: PresentationType;

pages/p/[slug].tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
PrevSlideButton,
1717
StartPresentationModeButton,
1818
} from "components";
19-
import { keyListeners } from "lib/setupKeyListeners";
19+
import { keyListeners } from "@lib/setupKeyListeners";
2020

2121
import "@uiw/react-md-editor/dist/markdown-editor.css";
2222
import "@uiw/react-markdown-preview/dist/markdown.css";

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"lib": ["es5", "es6"],
3+
"lib": ["es5", "es6", "ESNext"],
44
"target": "es5",
55
"module": "commonjs",
66
"moduleResolution": "node",

0 commit comments

Comments
 (0)