feat: ability to delete a project (#37)
This commit is contained in:
		| @@ -6,6 +6,6 @@ CREATE TABLE "tasks"( | ||||
| 	"deadline" DATE, | ||||
| 	"category" JSONB NOT NULL, | ||||
| 	"project_id" INT4, | ||||
| 	FOREIGN KEY ("project_id") REFERENCES "projects"("id") | ||||
| 	FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE SET NULL | ||||
| ); | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| use crate::models::project::{NewProject, Project}; | ||||
| use crate::server::projects::{create_project, edit_project}; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use crate::server::projects::{create_project, delete_project, edit_project}; | ||||
| use dioxus::core_macro::{component, rsx}; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::use_query_client; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn ProjectForm(project: Option<Project>, on_successful_submit: EventHandler<()>) | ||||
| @@ -25,9 +25,7 @@ pub(crate) fn ProjectForm(project: Option<Project>, on_successful_submit: EventH | ||||
|                     } else { | ||||
|                         let _ = create_project(new_project).await; | ||||
|                     } | ||||
|                     query_client.invalidate_queries(&[ | ||||
|                         QueryKey::Projects | ||||
|                     ]); | ||||
|                     query_client.invalidate_queries(&[QueryKey::Projects]); | ||||
|                     on_successful_submit.call(()); | ||||
|                 } | ||||
|             }, | ||||
| @@ -44,14 +42,31 @@ pub(crate) fn ProjectForm(project: Option<Project>, on_successful_submit: EventH | ||||
|                 input { | ||||
|                     name: "title", | ||||
|                     required: true, | ||||
|                     initial_value: project.map(|project| project.title().to_owned()), | ||||
|                     initial_value: project.as_ref().map(|project| project.title().to_owned()), | ||||
|                     r#type: "text", | ||||
|                     class: "py-2 px-3 grow bg-zinc-800/50 rounded-lg", | ||||
|                     id: "input_title" | ||||
|                 } | ||||
|             } | ||||
|             div { | ||||
|                 class: "flex flex-row justify-end mt-auto", | ||||
|                 class: "flex flex-row justify-between mt-auto", | ||||
|                 button { | ||||
|                     r#type: "button", | ||||
|                     class: "py-2 px-4 bg-zinc-300/50 rounded-lg", | ||||
|                     onclick: move |_| { | ||||
|                         let project = project.clone(); | ||||
|                         async move { | ||||
|                             if let Some(project) = project { | ||||
|                                 let _ = delete_project(project.id()).await; | ||||
|                                 query_client.invalidate_queries(&[QueryKey::Projects]); | ||||
|                             } | ||||
|                             on_successful_submit.call(()); | ||||
|                         } | ||||
|                     }, | ||||
|                     i { | ||||
|                         class: "fa-solid fa-trash-can" | ||||
|                     } | ||||
|                 } | ||||
|                 button { | ||||
|                     r#type: "submit", | ||||
|                     class: "py-2 px-4 bg-zinc-300/50 rounded-lg", | ||||
|   | ||||
| @@ -7,11 +7,17 @@ pub enum Error { | ||||
|     ServerInternal, | ||||
| } | ||||
|  | ||||
| impl From<diesel::result::Error> for Error { | ||||
|     fn from(_: diesel::result::Error) -> Self {  | ||||
|         Self::ServerInternal  | ||||
|     } | ||||
| } | ||||
|  | ||||
| // has to be implemented for Dioxus server functions | ||||
| impl Display for Error { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             Error::ServerInternal => write!(f, "internal server error"), | ||||
|             Self::ServerInternal => write!(f, "internal server error"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -22,7 +28,7 @@ impl FromStr for Error { | ||||
|  | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(match s { | ||||
|             "internal server error" => Error::ServerInternal, | ||||
|             "internal server error" => Self::ServerInternal, | ||||
|             _ => return Err(()), | ||||
|         }) | ||||
|     } | ||||
|   | ||||
| @@ -36,7 +36,7 @@ impl From<ValidationErrors> for ErrorVec<ProjectError> { | ||||
|  | ||||
| impl From<diesel::result::Error> for ProjectError { | ||||
|     fn from(_: diesel::result::Error) -> Self { | ||||
|         ProjectError::Error(Error::ServerInternal) | ||||
|         Self::Error(Error::ServerInternal) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -52,6 +52,6 @@ impl FromStr for ProjectError { | ||||
|     type Err = (); | ||||
|  | ||||
|     fn from_str(_: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(ProjectError::Error(Error::ServerInternal)) | ||||
|         Ok(Self::Error(Error::ServerInternal)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -42,12 +42,12 @@ impl From<diesel::result::Error> for TaskError { | ||||
|                 diesel::result::DatabaseErrorKind::ForeignKeyViolation, info | ||||
|             ) => { | ||||
|                 match info.constraint_name() { | ||||
|                     Some("tasks_project_id_fkey") => TaskError::ProjectNotFound, | ||||
|                     _ => TaskError::Error(Error::ServerInternal) | ||||
|                     Some("tasks_project_id_fkey") => Self::ProjectNotFound, | ||||
|                     _ => Self::Error(Error::ServerInternal) | ||||
|                 } | ||||
|             } | ||||
|             _ => { | ||||
|                 TaskError::Error(Error::ServerInternal) | ||||
|                 Self::Error(Error::ServerInternal) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -65,6 +65,6 @@ impl FromStr for TaskError { | ||||
|     type Err = (); | ||||
|  | ||||
|     fn from_str(_: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(TaskError::Error(Error::ServerInternal)) | ||||
|         Ok(Self::Error(Error::ServerInternal)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -71,3 +71,17 @@ pub(crate) async fn edit_project(project_id: i32, new_project: NewProject) | ||||
|  | ||||
|     Ok(updated_project) | ||||
| } | ||||
|  | ||||
| #[server] | ||||
| pub(crate) async fn delete_project(project_id: i32) | ||||
|     -> Result<(), ServerFnError<ErrorVec<Error>>> { | ||||
|     use crate::schema::projects::dsl::*; | ||||
|  | ||||
|     let mut connection = establish_database_connection() | ||||
|         .map_err::<ErrorVec<Error>, _>(|_| vec![Error::ServerInternal].into())?; | ||||
|  | ||||
|     diesel::delete(projects.filter(id.eq(project_id))).execute(&mut connection) | ||||
|         .map_err::<ErrorVec<Error>, _>(|error| vec![error.into()].into())?; | ||||
|      | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user