1use std::fmt;
2use crate::clockify::Config;
3use crate::api::{
4 EndPoint,
5 task::Task,
6 common::{Rate, Membership},
7};
8use crate::error::Error;
9use crate::ui::components::Id;
10use serde::{Serialize, Deserialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13#[serde(rename_all = "camelCase")]
14pub struct Project {
15 pub id: Option<String>,
16 pub name: String,
17 pub hourly_rate: Option<Rate>,
18 pub client_id: Option<String>,
19 pub client: Option<String>,
20 pub workspace_id: Option<String>,
21 pub billable: Option<bool>,
22 pub memberships: Option<Vec<Membership>>,
23 pub color: Option<String>,
24 pub estimate: Option<Estimate>,
25 pub archived: Option<bool>,
26 pub tasks: Option<Vec<Task>>,
27 pub note: Option<String>,
28 pub duration: Option<String>,
29 pub cost_rate: Option<String>,
30 pub time_estimate: Option<TimeEstimate>,
31 pub budget_estimate: Option<String>,
32 pub custom_fields: Option<Vec<CustomField>>,
33 pub public: Option<bool>,
34 pub template: Option<bool>,
35 pub favorite: Option<bool>
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, Default)]
39#[serde(rename_all = "camelCase")]
40pub struct Estimate {
41 pub estimate: String,
42 pub r#type: String
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, Default)]
46#[serde(rename_all = "camelCase")]
47pub struct TimeEstimate {
48 pub estimate: String,
49 pub r#type: String,
50 pub reset_option: Option<String>,
51 pub active: bool,
52 pub include_non_billable: bool
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, Default)]
56#[serde(rename_all = "camelCase")]
57pub struct CustomField {
58 pub custom_field_id: String,
59 pub name: String,
60 pub r#type: String,
61 pub value: String,
62 pub status: String
63}
64
65impl From<&str> for Project {
66 fn from(s: &str) -> Project {
67 Project { name: s.to_string(), ..Default::default() }
68 }
69}
70
71impl fmt::Display for Project {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "{}", self.name)
74 }
75}
76
77impl Id for Project {
78 fn id(&self) -> String {
79 return self.id.as_ref().unwrap().clone();
80 }
81}
82
83impl EndPoint for Project {
84 fn endpoint(config: &Config) -> Result<String, Error> {
85 Ok(format!("/workspaces/{}/projects", config.workspace_id.as_ref().ok_or(Error::MissingWorkspace)?.clone()))
86 }
87}