Add base project
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing

This commit is contained in:
Kasper Juul Hermansen 2021-11-15 13:50:38 +01:00
parent 55ee0516da
commit f6331c8aea
Signed by: kjuulh
GPG Key ID: 0F95C140730F2F23
14 changed files with 63 additions and 35 deletions

View File

@ -17,7 +17,7 @@ public class TodosController : ControllerBase
[HttpPost]
public async Task<ActionResult<Core.Entities.Todo>> CreateTodo([FromBody] CreateTodoRequest request) =>
Ok(await _todoRepository.CreateTodoAsync(request.Title));
Ok(await _todoRepository.CreateTodoAsync(request.Title, String.Empty));
[HttpGet]
public async Task<ActionResult<IEnumerable<Core.Entities.Todo>>> GetTodos() =>

View File

@ -11,5 +11,8 @@ public record TodoResponse
public string Title { get; init; }
[JsonPropertyName("status")]
public bool Status { get; init; }
public bool Status { get; init; }
[JsonPropertyName("project")]
public string Project { get; set; }
}

View File

@ -14,14 +14,14 @@ namespace Todo.Api.Hubs
_todoRepository = todoRepository;
}
public async Task CreateTodo(string todoTitle)
public async Task CreateTodo(string todoTitle, string projectName)
{
var _ = await _todoRepository.CreateTodoAsync(todoTitle);
var _ = await _todoRepository.CreateTodoAsync(todoTitle, projectName);
var todos = await _todoRepository.GetNotDoneTodos();
var serializedTodos =
JsonSerializer.Serialize(todos
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title })
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Project = t.Project })
.ToList());
await Clients.Caller.SendAsync("getInboxTodos", serializedTodos);
@ -34,7 +34,8 @@ namespace Todo.Api.Hubs
var todos = await _todoRepository.GetNotDoneTodos();
var serializedTodos =
JsonSerializer.Serialize(todos
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Status = t.Status })
.Select(t => new TodoResponse
{ Id = t.Id, Title = t.Title, Status = t.Status, Project = t.Project })
.ToList());
await Clients.Caller.SendAsync("getInboxTodos", serializedTodos);
@ -44,7 +45,7 @@ namespace Todo.Api.Hubs
{
var todos = await _todoRepository.GetTodosAsync();
var serializedTodos = JsonSerializer.Serialize(todos
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Status = t.Status })
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Status = t.Status, Project = t.Project })
.ToList());
await Clients.Caller.SendAsync("todos", serializedTodos);
@ -55,7 +56,7 @@ namespace Todo.Api.Hubs
{
var todos = await _todoRepository.GetNotDoneTodos();
var serializedTodos = JsonSerializer.Serialize(todos
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Status = t.Status })
.Select(t => new TodoResponse { Id = t.Id, Title = t.Title, Status = t.Status, Project = t.Project })
.ToList());
await Clients.Caller.SendAsync("getInboxTodos", serializedTodos);

View File

@ -5,4 +5,5 @@ public record Todo
public string Id { get; init; }
public string Title { get; init; }
public bool Status { get; init; }
public string Project { get; init; }
}

View File

@ -2,7 +2,7 @@ namespace Todo.Core.Interfaces.Persistence;
public interface ITodoRepository
{
Task<Entities.Todo> CreateTodoAsync(string title);
Task<Entities.Todo> CreateTodoAsync(string title, string projectName);
Task<IEnumerable<Entities.Todo>> GetTodosAsync();
Task UpdateTodoStatus(string todoId, bool todoStatus);
Task<IEnumerable<Entities.Todo>> GetNotDoneTodos();

View File

@ -11,4 +11,5 @@ public record MongoTodo
[BsonRequired] public string Title { get; init; }
[BsonRequired] public bool Status { get; set; }
public string ProjectName { get; set; } = String.Empty;
}

View File

@ -15,11 +15,12 @@ public class TodoRepository : ITodoRepository
_todosCollection = database.GetCollection<MongoTodo>("todos");
}
public async Task<Core.Entities.Todo> CreateTodoAsync(string title)
public async Task<Core.Entities.Todo> CreateTodoAsync(string title, string projectName)
{
var todo = new MongoTodo() { Title = title };
var todo = new MongoTodo() { Title = title, ProjectName = projectName };
await _todosCollection.InsertOneAsync(todo);
return new Core.Entities.Todo() { Id = todo.Id, Title = todo.Title, Status = false};
return new Core.Entities.Todo()
{ Id = todo.Id, Title = todo.Title, Status = false, Project = todo.ProjectName };
}
public async Task<IEnumerable<Core.Entities.Todo>> GetTodosAsync()
@ -28,14 +29,14 @@ public class TodoRepository : ITodoRepository
return todos
.ToEnumerable()
.Select(t =>
new Core.Entities.Todo() { Id = t.Id, Title = t.Title, Status = t.Status});
new Core.Entities.Todo() { Id = t.Id, Title = t.Title, Status = t.Status, Project = t.ProjectName });
}
public async Task UpdateTodoStatus(string todoId, bool todoStatus)
{
await _todosCollection
.UpdateOneAsync(t => t.Id == todoId,
Builders<MongoTodo>.Update.Set(t => t.Status, todoStatus));
Builders<MongoTodo>.Update.Set(t => t.Status, todoStatus));
}
public async Task<IEnumerable<Core.Entities.Todo>> GetNotDoneTodos()

View File

@ -21,8 +21,8 @@ export function AddTodo(props: {}) {
return (
<AddTodoForm
onAdd={(todoName) => {
createTodo(todoName);
onAdd={(todoName, project) => {
createTodo(todoName, project);
}}
onClose={() => setCollapsed(CollapsedState.collapsed)}
/>

View File

@ -1,30 +1,43 @@
import { FC, useState } from "react";
export const AddTodoForm: FC<{
onAdd: (todoName: string) => void;
onAdd: (todoName: string, project: string) => void;
onClose: () => void;
}> = ({ onAdd, onClose }) => {
const [todoName, setTodoName] = useState("");
const [project, setProject] = useState("");
return (
<form
onSubmit={(e) => {
e.preventDefault();
onAdd(todoName);
onAdd(todoName, project);
setTodoName("");
}}
>
<div className="py-2 space-y-3">
<div className="todo-input-form py-2 px-4 bg-gray-800 border border-gray-500 rounded-lg">
<input
type="text"
placeholder="Todo name"
className="text-sm w-full"
autoFocus
value={todoName}
tabIndex={1}
onChange={(e) => setTodoName(e.target.value)}
/>
<div className="flex flex-col md:flex-row gap-4">
<div className="todo-input-form md:flex-grow py-2 px-4 bg-gray-800 border border-gray-500 rounded-lg">
<input
type="text"
placeholder="Todo name"
className="text-sm w-full"
autoFocus
value={todoName}
tabIndex={1}
onChange={(e) => setTodoName(e.target.value)}
/>
</div>
<div className="todo-project py-2 px-4 bg-gray-700 border border-gray-500 rounded-lg ">
<input
type="text"
placeholder="Project name"
className="text-sm w-full placeholder-gray-400"
value={project}
tabIndex={2}
onChange={(e) => setProject(e.target.value)}
/>
</div>
</div>
<div className="space-x-2">
<button

View File

@ -5,13 +5,19 @@ import { TodoCheckmark } from "@src/components/todos/todoCheckmark";
interface TodoItemProps {
todo: Todo;
updateTodo: (todo: Todo) => void;
displayProject: boolean;
}
export const TodoItem: FC<TodoItemProps> = (props) => (
<div className="py-3 border-b border-gray-300 dark:border-gray-600">
<div className="flex items-center space-x-4">
<TodoCheckmark {...props} />
<span className="pb-1">{props.todo.title}</span>
<div className="flex flex-row flex-grow gap-2 pr-6">
<div className="flex-grow w-full break-all">{props.todo.title}</div>
{props.displayProject && props.todo.project && (
<div className="text-gray-500 text-right">{props.todo.project}</div>
)}
</div>
</div>
</div>
);

View File

@ -18,6 +18,7 @@ export const TodoList = (props: { todos: Todo[]; hideDone: boolean }) => {
updateTodo={(todo) => {
updateTodoState(todo.id, todo.status);
}}
displayProject={false}
/>
</li>
))}

View File

@ -10,6 +10,7 @@ export interface Todo {
id: string;
title: string;
status: StatusState;
project?: string;
}
export const asTodo = (item: Todo): Todo => {

View File

@ -12,7 +12,7 @@ interface SocketContextProps {
inboxTodos: Todo[];
getTodos: () => void;
getInboxTodos: () => void;
createTodo: (todoName: string) => void;
createTodo: (todoName: string, project: string) => void;
updateTodo: (todoId: string, todoStatus: StatusState) => void;
}
@ -22,7 +22,7 @@ export const SocketContext = createContext<SocketContextProps>({
inboxTodos: [],
getTodos: () => {},
getInboxTodos: () => {},
createTodo: (todoName) => {},
createTodo: (todoName, project) => {},
updateTodo: (todoId, todoStatus) => {},
});
@ -72,8 +72,8 @@ export const SocketProvider: FC = (props) => {
getInboxTodos: () => {
conn.invoke("GetInboxTodos").catch(console.error);
},
createTodo: (todoName) => {
conn.invoke("CreateTodo", todoName).catch(console.error);
createTodo: (todoName, project) => {
conn.invoke("CreateTodo", todoName, project).catch(console.error);
},
updateTodo: (todoId, todoStatus) => {
conn.invoke("UpdateTodo", todoId, todoStatus).catch(console.error);

View File

@ -19,8 +19,8 @@ export const useCreateTodo = () => {
const socketContext = useContext(SocketContext);
return {
createTodo: (todoName: string) => {
socketContext.createTodo(todoName);
createTodo: (todoName: string, project: string) => {
socketContext.createTodo(todoName, project);
},
};
};