Skip to content

Commit

Permalink
Merge branch 'care-instructions'
Browse files Browse the repository at this point in the history
  • Loading branch information
calejvaldez committed Nov 14, 2024
2 parents 01786c2 + 83da8a1 commit c1a7045
Show file tree
Hide file tree
Showing 16 changed files with 714 additions and 11 deletions.
Binary file added public/images/icon_care_instructions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 99 additions & 0 deletions src-tauri/src/care_instructions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// care_instructions.rs
// Ojos Project
//
// Extra care instructions provided by the caregivers for the nurses.
use crate::structs::CareInstruction;
use chrono::Local;
use rusqlite::{named_params, Connection};
use tauri::{AppHandle, Manager};
use uuid::Uuid;

pub fn add_care_instruction(
app: &AppHandle,
title: String,
content: String,
frequency: Option<String>,
added_by: String,
) -> CareInstruction {
let app_data_dir = app.path().app_data_dir().unwrap();
let conn = Connection::open(app_data_dir.join("iris.db")).unwrap();
let ts = Local::now().timestamp();
let id = Uuid::new_v4().to_string();

let ci = CareInstruction {
id,
title,
content,
frequency,
added_by,
last_updated: ts,
};

conn.execute("INSERT INTO care_instruction(id, title, content, frequency, added_by, last_updated) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", (&ci.id, &ci.title, &ci.content, &ci.frequency, &ci.added_by, &ci.last_updated)).unwrap();
ci
}

pub fn update_care_instructions(
app: &AppHandle,
id: String,
title: String,
content: String,
frequency: Option<String>,
added_by: String,
) -> CareInstruction {
let app_data_dir = app.path().app_data_dir().unwrap();
let conn = Connection::open(app_data_dir.join("iris.db")).unwrap();
let ts = Local::now().timestamp();

let ci = CareInstruction {
id,
title,
content,
frequency,
added_by,
last_updated: ts,
};

conn.execute(
"UPDATE care_instruction SET title=:title, content=:content, frequency=:frequency, added_by=:added_by, last_updated=:last_updated WHERE id=:id",
named_params! {
":id": &ci.id,
":title": &ci.title,
":content": &ci.content,
":frequency": &ci.frequency,
":added_by": &ci.added_by,
":last_updated": &ci.last_updated
},
)
.unwrap();

ci
}

pub fn get_all_care_instructions(app: &AppHandle) -> Vec<CareInstruction> {
let app_data_dir = app.path().app_data_dir().unwrap();
let conn = Connection::open(app_data_dir.join("iris.db")).unwrap();

let mut stmt = conn
.prepare("SELECT * FROM care_instruction ORDER BY last_updated DESC")
.unwrap();
let matched_ci = stmt
.query_map([], |row| {
Ok(CareInstruction {
id: row.get(0)?,
title: row.get(1)?,
content: row.get(2)?,
frequency: row.get(3)?,
added_by: row.get(4)?,
last_updated: row.get(5)?,
})
})
.unwrap();

let mut vec_to_return: Vec<CareInstruction> = vec![];
for ci in matched_ci {
vec_to_return.push(ci.unwrap());
}

vec_to_return
}
146 changes: 145 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod care_instructions;
mod config;
mod dev;
mod medications;
Expand Down Expand Up @@ -95,6 +96,144 @@ fn create_user(app: AppHandle, name: String, user_type: String) {
User::create(app, name, user_type);
}

/// # `get_all_care_instructions` Command
///
/// Returns a `CareInstruction[]`.
///
/// ## TypeScript Usage
///
/// ```typescript
/// invoke('get_all_care_instructions').then(ci => {
/// setCareInstructions(ci as CareInstruction[]);
/// });
/// ```
#[tauri::command]
fn get_all_care_instructions(app: AppHandle) -> Vec<structs::CareInstruction> {
care_instructions::get_all_care_instructions(&app)
}

/// # `get_single_care_instruction` command
///
/// Returns a single care instructions, with the provided `id`.
///
/// ## TypeScript
///
/// ```typescript
/// invoke('get_single_care_instruction', {id: ''}).then(ci => {
/// if (ci) { // this COULD return a null, check!
/// setCareInstruction(ci as CareInstruction);
/// }
///
/// });
/// ```
#[tauri::command(rename_all = "snake_case")]
fn get_single_care_instruction(app: AppHandle, id: String) -> Option<structs::CareInstruction> {
for instruction in care_instructions::get_all_care_instructions(&app) {
if instruction.id == id {
return Some(instruction);
}
}
return None;
}

/// # `create_care_instructions` Command
///
/// Creates a new `CareInstruction` and returns it
///
/// ## TypeScript Usage
///
/// ```typescript
/// invoke('create_care_instructions', {
/// title: 'Move Patient',
/// content: 'Please help her move once in a while.',
/// frequency: 'Once daily',
/// added_by: 'nurse_id'
/// }).then(ci => {
/// setCareInstructions(ci as CareInstruction);
/// })
/// ```
#[tauri::command(rename_all = "snake_case")]
fn create_care_instructions(
app: AppHandle,
title: String,
content: String,
frequency: Option<String>,
added_by: String,
) -> structs::CareInstruction {
care_instructions::add_care_instruction(&app, title, content, frequency, added_by)
}

/// # `update_care_instructions` Command
///
/// Updates a single `CareInstruction` and returns it.
///
/// ## TypeScript
///
/// ```typescript
/// invoke('update_care_instructions', {
/// id: 'uuid',
/// title: 'Move Patient (Edited)',
/// content: 'Please help her move once in a while.',
/// frequency: 'Once daily',
/// added_by: 'nurse_id'
/// }).then(ci => {
/// setCareInstructions(ci as CareInstruction);
/// })
/// ```
#[tauri::command(rename_all = "snake_case")]
fn update_care_instructions(
app: AppHandle,
id: String,
title: String,
content: String,
frequency: Option<String>,
added_by: String,
) -> structs::CareInstruction {
care_instructions::update_care_instructions(&app, id, title, content, frequency, added_by)
}

/// # `care_instructions_previous_next_ids` Command
///
/// Returns an array with the `CareInstruction.id` of the previous and next
/// care instruction for the "Previous Topic" and "Next Topic" buttons. Index
/// 0 is the previous ID, index 1 is the next ID.
///
/// ## TypeScript
///
/// ```typescript
/// invoke('care_instructions_previous_next_ids', {id: 'uuid'}).then(previousNext => {
/// setPreviousTopic(previousNext[0]);
/// setNextTopic(previousNext[1]);)
/// })
/// ```
#[tauri::command(rename=all = "snake_case")]
fn care_instructions_previous_next_ids(app: AppHandle, id: String) -> Vec<String> {
let instructions = care_instructions::get_all_care_instructions(&app);
let mut previous = 0;
let mut next = 0;
for (index, instruction) in instructions.iter().enumerate() {
if instruction.id == id {
if instructions.len() == 1 {
[previous, next] = [0, 0]
} else if index == 0 {
previous = instructions.len() - 1;
next = index + 1;
} else if index == instructions.len() - 1 {
previous = index - 1;
next = 0;
} else {
previous = index - 1;
next = index + 1;
}
}
}

return vec![
(&instructions[previous]).id.clone(),
(&instructions[next]).id.clone(),
];
}

fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
Expand All @@ -104,7 +243,12 @@ fn main() {
get_config,
get_resources,
complete_onboarding,
create_user
create_user,
get_all_care_instructions,
create_care_instructions,
get_single_care_instruction,
update_care_instructions,
care_instructions_previous_next_ids
])
.setup(|app| {
app.set_menu(menu(app.app_handle().clone())).unwrap();
Expand Down
18 changes: 11 additions & 7 deletions src-tauri/src/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,23 @@ CREATE TABLE IF NOT EXISTS patient_recorded_outcome (

/*
care_instruction
Extra care instructions provided by the caregivers for the nurses
Extra care instructions provided by the caregivers for the nurses.
Rows:
* text - The instruction in plaintext
frequency - The frequency this should be done, defaults to `AS NEEDED`
added_by - The name of the individual that requested these instructions
first_added - The Unix timestamp of when this was added
* id - A UUID
title - Short title for the instruction
content - A more detailed description of the instruction.
frequency - A readable format, such as "Once daily"
added_by - A User.id
last_updated - A Unix timestamp indicating the last edit
*/
CREATE TABLE IF NOT EXISTS care_instruction (
text TEXT NOT NULL PRIMARY KEY,
id TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
frequency TEXT,
added_by TEXT NOT NULL,
first_added INTEGER NOT NULL
last_updated INTEGER NOT NULL
) STRICT;

/*
Expand Down
13 changes: 13 additions & 0 deletions src-tauri/src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,16 @@ pub struct Resource {
pub category: String,
pub last_updated: f32,
}

/// # `CareInstruction` struct
///
/// Extra care instructions provided by the caregivers for the nurses.
#[derive(Serialize, Deserialize)]
pub struct CareInstruction {
pub id: String,
pub title: String,
pub content: String,
pub frequency: Option<String>,
pub added_by: String,
pub last_updated: i64,
}
7 changes: 7 additions & 0 deletions src/app/HubApps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ export const HubApps: HubAppProps[] = [
name: "Resources",
icon: "/images/icon_resources.png",
},

// Extra care instructions provided by the caregivers for the nurses.
{
link: "./care_instructions",
name: "Care Instructions",
icon: "/images/icon_care_instructions.png",
},
].sort((a, b) => {
// Sorts list by HubAppProps.name
return a.name.localeCompare(b.name);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
CareInstructionButton.module.css
Ojos Project
*/
.single_care_instruction {
width: 65dvw;
margin: 20px 0;
overflow-wrap: anywhere;
}

.single_care_instruction:hover {
cursor: pointer;
}

.tap_message {
font-size: 14px;
color: grey;
}
26 changes: 26 additions & 0 deletions src/app/care_instructions/components/CareInstructionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// CareInstructionButton.tsx
// Ojos Project
import { CareInstruction } from "@/types";
import classes from "./CareInstructionButton.module.css";
import Link from "next/link";

export default function CareInstructionButton(props: {
instruction: CareInstruction;
}) {
return (
<Link
style={{ color: "black", textDecoration: "none" }}
href={{
pathname: "./care_instructions/view/",
query: { id: props.instruction.id },
}}
>
<div className={classes.single_care_instruction}>
<h3>{props.instruction.title}</h3>
<p>{props.instruction.content}</p>

<p className={classes.tap_message}>Tap for more...</p>
</div>
</Link>
);
}
Loading

0 comments on commit c1a7045

Please sign in to comment.