Update with more optimistic updates
This commit is contained in:
parent
bb99f99a22
commit
3c5fe488cd
@ -37,11 +37,15 @@ public class TodosController : ApiController
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> CreateTodo(
|
||||
[FromBody] CreateTodoRequest request)
|
||||
=> Ok(await Mediator.Send(request.To()));
|
||||
{
|
||||
return Ok(await Mediator.Send(request.To()));
|
||||
}
|
||||
|
||||
[HttpGet("{todoId}")]
|
||||
public async Task<ActionResult<TodoViewModel>> GetTodoById([FromRoute] string todoId)
|
||||
=> await Mediator.Send(new GetTodoByIdQuery(todoId));
|
||||
{
|
||||
return await Mediator.Send(new GetTodoByIdQuery(todoId));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<TodoViewModel>>> GetTodos([FromQuery] bool onlyActive = false)
|
||||
|
@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using MediatR;
|
||||
using Todo.Core.Application.Notifications.Todo;
|
||||
using Todo.Core.Application.Queries.Todos;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
using Todo.Core.Interfaces.User;
|
||||
|
||||
@ -10,9 +11,9 @@ namespace Todo.Core.Application.Commands.Todo;
|
||||
public record CreateTodoCommand(
|
||||
[Required] string TodoTitle,
|
||||
string? TodoProject,
|
||||
string? TodoDescription) : IRequest<string>
|
||||
string? TodoDescription) : IRequest<TodoViewModel>
|
||||
{
|
||||
internal class Handler : IRequestHandler<CreateTodoCommand, string>
|
||||
internal class Handler : IRequestHandler<CreateTodoCommand, TodoViewModel>
|
||||
{
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
private readonly IMediator _mediator;
|
||||
@ -28,7 +29,7 @@ public record CreateTodoCommand(
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task<string> Handle(
|
||||
public async Task<TodoViewModel> Handle(
|
||||
CreateTodoCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@ -47,7 +48,7 @@ public record CreateTodoCommand(
|
||||
new TodoCreated(todo.Id),
|
||||
cancellationToken);
|
||||
|
||||
return todo.Id;
|
||||
return TodoViewModel.From(todo);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":3,"file":"sw.js","sources":["../../../../../../../../tmp/2966604b4704df68e7ceebb70ae0c809/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/home/kjuulh/git/git.front.kjuulh.io/kjuulh/todo/src/client/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/home/kjuulh/git/git.front.kjuulh.io/kjuulh/todo/src/client/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/home/kjuulh/git/git.front.kjuulh.io/kjuulh/todo/src/client/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/home/kjuulh/git/git.front.kjuulh.io/kjuulh/todo/src/client/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({request, response, event, state}) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, {status: 200, statusText: 'OK', headers: response.headers}); } return response; } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGiK;EACjK;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAGAA,aAAa;EAUbC,IAAI,CAACC,WAAL;AAEAC,sBAAyB;AAIzBC,uBAA6B,CAAC,GAAD,EAAM,IAAIC,oBAAJ,CAAoC;EAAE,eAAY,WAAd;EAA2BC,EAAAA,OAAO,EAAE,CAAC;EAAEC,IAAAA,eAAe,EAAE,OAAO;EAACC,MAAAA,OAAD;EAAUC,MAAAA,QAAV;EAAoBC,MAAAA,KAApB;EAA2BC,MAAAA;EAA3B,KAAP,KAA6C;EAAE,UAAIF,QAAQ,IAAIA,QAAQ,CAACG,IAAT,KAAkB,gBAAlC,EAAoD;EAAE,eAAO,IAAIC,QAAJ,CAAaJ,QAAQ,CAACK,IAAtB,EAA4B;EAACC,UAAAA,MAAM,EAAE,GAAT;EAAcC,UAAAA,UAAU,EAAE,IAA1B;EAAgCC,UAAAA,OAAO,EAAER,QAAQ,CAACQ;EAAlD,SAA5B,CAAP;EAAiG;;EAAC,aAAOR,QAAP;EAAkB;EAA5O,GAAD;EAApC,CAApC,CAAN,EAAmU,KAAnU,CAA7B;AACAL,uBAA6B,CAAC,KAAD,EAAQ,IAAIc,mBAAJ,CAAmC;EAAE,eAAY,KAAd;EAAqBZ,EAAAA,OAAO,EAAE;EAA9B,CAAnC,CAAR,EAAgF,KAAhF,CAA7B;;"}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1
src/client/public/workbox-4a677df8.js
Normal file
1
src/client/public/workbox-4a677df8.js
Normal file
File diff suppressed because one or more lines are too long
@ -21,7 +21,9 @@ export const TodoItem: FC<TodoItemProps> = (props) => {
|
||||
<div
|
||||
className="py-3 border-b border-gray-300 dark:border-gray-600 relative"
|
||||
onMouseEnter={() => {
|
||||
prefetchTodo(props.todo.id);
|
||||
if (!props.todo.id.startsWith("temp")) {
|
||||
prefetchTodo(props.todo.id);
|
||||
}
|
||||
setIsHovering(true);
|
||||
}}
|
||||
onMouseLeave={() => setIsHovering(false)}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import { baseQueryWithReauth } from "@src/infrastructure/apis/utilities";
|
||||
import { Todo } from "@src/core/entities/todo";
|
||||
import { nanoid } from "@reduxjs/toolkit";
|
||||
|
||||
export const todosApi = createApi({
|
||||
reducerPath: "api",
|
||||
@ -12,7 +13,7 @@ export const todosApi = createApi({
|
||||
providesTags: (result, error, id) => [{ type: "todo", id }],
|
||||
}),
|
||||
|
||||
getAllTodos: build.query<Todo[], void>({
|
||||
getAllTodos: build.query<Todo[], string>({
|
||||
query: () => ({ url: `api/todos` }),
|
||||
providesTags: (result) =>
|
||||
result
|
||||
@ -39,7 +40,7 @@ export const todosApi = createApi({
|
||||
: [],
|
||||
}),
|
||||
|
||||
createTodo: build.mutation<string, Partial<Todo>>({
|
||||
createTodo: build.mutation<Todo, Todo>({
|
||||
query(body) {
|
||||
return {
|
||||
url: "/api/todos",
|
||||
@ -47,7 +48,44 @@ export const todosApi = createApi({
|
||||
body,
|
||||
};
|
||||
},
|
||||
invalidatesTags: (result, error, id) => [{ type: "todo", id: "LIST" }],
|
||||
invalidatesTags: (result, error, id) => [{ type: "todo", id: result.id }],
|
||||
async onQueryStarted({ id, ...body }, { dispatch, queryFulfilled }) {
|
||||
const tempId = nanoid();
|
||||
const replaceGetAllResult = dispatch(
|
||||
todosApi.util.updateQueryData(
|
||||
"getActiveTodos",
|
||||
undefined,
|
||||
(draft) => {
|
||||
const todo: Todo = { id: "temp" + tempId, ...body };
|
||||
if (todo) {
|
||||
draft.push(todo);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
const data = await queryFulfilled;
|
||||
const finishUpdated = dispatch(
|
||||
todosApi.util.updateQueryData(
|
||||
"getActiveTodos",
|
||||
undefined,
|
||||
(draft) => {
|
||||
const todo = draft.find((t) => t.id == "temp" + tempId);
|
||||
if (todo) {
|
||||
Object.assign(todo, data.data);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
replaceGetAllResult.undo();
|
||||
dispatch(
|
||||
todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }])
|
||||
);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
replaceTodo: build.mutation<string, Partial<Todo>>({
|
||||
@ -67,11 +105,28 @@ export const todosApi = createApi({
|
||||
})
|
||||
);
|
||||
|
||||
const replaceGetAllResult = dispatch(
|
||||
todosApi.util.updateQueryData(
|
||||
"getActiveTodos",
|
||||
undefined,
|
||||
(draft) => {
|
||||
const todo = draft.find((t) => t.id === id);
|
||||
if (todo) {
|
||||
Object.assign(todo, body);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
await queryFulfilled;
|
||||
} catch {
|
||||
replaceGetAllResult.undo();
|
||||
replaceResult.undo();
|
||||
dispatch(todosApi.util.invalidateTags([{ type: "todo", id }]));
|
||||
dispatch(
|
||||
todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }])
|
||||
);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
@ -25,7 +25,7 @@ export const SocketProvider: FC = (props) => {
|
||||
const { todoId } = JSON.parse(todoCreated) as { todoId: string };
|
||||
if (todoId) {
|
||||
dispatch(todosApi.endpoints.getTodoById.initiate(todoId));
|
||||
dispatch(todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }]));
|
||||
// dispatch(todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }]));
|
||||
}
|
||||
});
|
||||
|
||||
@ -33,7 +33,7 @@ export const SocketProvider: FC = (props) => {
|
||||
const { todoId } = JSON.parse(todoUpdated) as { todoId: string };
|
||||
if (todoId) {
|
||||
dispatch(todosApi.util.invalidateTags([{ type: "todo", id: todoId }]));
|
||||
dispatch(todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }]));
|
||||
// dispatch(todosApi.util.invalidateTags([{ type: "todo", id: "LIST" }]));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { useAppSelector } from "@src/infrastructure/store";
|
||||
import { todosSelectors } from "@src/infrastructure/state/todo";
|
||||
import { todosApi } from "@src/infrastructure/apis/todosApi";
|
||||
import { Todo } from "@src/core/entities/todo";
|
||||
import { nanoid } from "@reduxjs/toolkit";
|
||||
|
||||
export const useSelectInboxTodos = () => {
|
||||
const todos = useAppSelector(todosSelectors.selectAll);
|
||||
@ -19,6 +20,9 @@ export const useCreateTodo = () => {
|
||||
return {
|
||||
createTodo: (todoName: string, project: string, description: string) => {
|
||||
createTodo({
|
||||
id: nanoid(),
|
||||
created: 0,
|
||||
status: false,
|
||||
title: todoName,
|
||||
project,
|
||||
description,
|
||||
|
Loading…
Reference in New Issue
Block a user