diff --git a/Cargo.lock b/Cargo.lock index e32fa8a..e8ae8e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1639,6 +1639,7 @@ dependencies = [ "atoi", "byteorder", "bytes", + "chrono", "crc", "crossbeam-queue", "dotenvy", @@ -1701,6 +1702,7 @@ dependencies = [ "sha2", "sqlx-core", "sqlx-mysql", + "sqlx-postgres", "sqlx-sqlite", "syn 1.0.109", "tempfile", @@ -1719,6 +1721,7 @@ dependencies = [ "bitflags 2.4.1", "byteorder", "bytes", + "chrono", "crc", "digest", "dotenvy", @@ -1760,6 +1763,7 @@ dependencies = [ "base64", "bitflags 2.4.1", "byteorder", + "chrono", "crc", "dotenvy", "etcetera", @@ -1796,6 +1800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" dependencies = [ "atoi", + "chrono", "flume", "futures-channel", "futures-core", diff --git a/Cargo.toml b/Cargo.toml index 856f119..cb20be6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ actix-web = "4.4.0" chrono = "0.4.31" maud = { version = "0.25.0", features = [ "actix-web" ] } serde = { version = "1.0.192", features = [ "derive" ] } -sqlx = { version = "0.7.3", features = ["sqlite", "runtime-tokio"] } +sqlx = { version = "0.7.3", features = [ "chrono", "sqlite", "runtime-tokio" ] } tokio = { version = "1.34.0", features = [ "full" ] } [profile.dev] diff --git a/src/index.rs b/src/index.rs index c165151..08ce52b 100644 --- a/src/index.rs +++ b/src/index.rs @@ -9,6 +9,47 @@ use maud::{ async fn index() -> web::Result { Ok(html! { (DOCTYPE) - h1 { "Hello, World!" } + + style {r#" + body { + font-family: sans; + background-color: #f4f4f4; + margin: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + } + + h1 { + text-align: center; + color: #333; + } + + .links { + text-align: center; + margin-top: 30px; + } + + .links a { + display: inline-block; + margin: 10px; + padding: 8px 16px; + text-decoration: none; + color: #fff; + background-color: #4caf50; + border-radius: 4px; + transition: background-color 0.3s ease; + } + + .links a:hover { + background-color: #45a049; + } + "#} + + div class="links" { + a href="/submit" { "Hatırlatıcı Koy" } + a href="/view" { "Hatırlatıcıları Görüntüle" } + } }) } diff --git a/src/main.rs b/src/main.rs index 857344d..f7870fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,21 +12,25 @@ use sqlx::{ #[web::main] async fn main() -> io::Result<()> { - let db = SqlitePool::connect_with(SqliteConnectOptions::new().filename("data.db")) - .await - .unwrap(); + let db = SqlitePool::connect_with( + SqliteConnectOptions::new() + .filename("data.db") + .create_if_missing(true), + ) + .await + .expect("Failed to connect to SQLite database."); sqlx::query( r" CREATE TABLE IF NOT EXISTS reminders ( - date INTEGET NOT NULL, - message TEXT NOT NULL + date DATETIME NOT NULL, + message TEXT NOT NULL ) ", ) .execute(&db) .await - .unwrap(); + .expect("Failed to create table reminders."); web::HttpServer::new(move || { web::App::new() diff --git a/src/submit.rs b/src/submit.rs index 39ac863..8495c41 100644 --- a/src/submit.rs +++ b/src/submit.rs @@ -11,6 +11,7 @@ use maud::{ DOCTYPE, }; use sqlx::SqlitePool; + #[derive(Debug, serde::Deserialize)] pub struct Reminder { date: String, @@ -24,6 +25,8 @@ async fn submit_form( ) -> web::Result { println!("{reminder:?}"); + let date_time = NaiveDateTime::parse_from_str(&reminder.date, "%Y-%m-%dT%H:%M").unwrap(); + sqlx::query( r" INSERT INTO @@ -32,11 +35,7 @@ async fn submit_form( (?, ?) ", ) - .bind( - NaiveDateTime::parse_from_str(&reminder.date, "%Y-%m-%dT%H:%M") - .unwrap() - .timestamp() as i64, - ) + .bind(date_time) .bind(reminder.message) .execute(&**data) .await @@ -44,6 +43,30 @@ async fn submit_form( Ok(html! { (DOCTYPE) + + style {r#" + body { + font-family: sans; + background-color: #f4f4f4; + margin: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + flex-direction: column; + } + + h1 { + color: #333; + margin-bottom: 20px; + } + + p { + color: #666; + margin-bottom: 40px; + } + "#} + h1 { "Kaydedildi." } p { "Ana sayfaya geri yönlendiriliyorsun..." } script type="text/javascript" {(PreEscaped(r#" @@ -56,6 +79,53 @@ async fn submit_form( async fn submit() -> web::Result { Ok(html! { (DOCTYPE) + + style {r#" + body { + font-family: sans; + background-color: #f4f4f4; + margin: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + } + + form { + background-color: #fff; + padding: 20px; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + } + + label { + display: block; + margin-bottom: 8px; + } + + input { + width: 100%; + padding: 8px; + margin-bottom: 16px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 4px; + } + + button { + background-color: #4caf50; + color: #fff; + padding: 10px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + } + + button:hover { + background-color: #45a049; + } + "#} + form action="/submit-form" { button type="submit" { "Kaydet" } br; diff --git a/src/view.rs b/src/view.rs index ad0be63..ac1cc1e 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,43 +1,90 @@ use actix_web as web; -use actix_web::web::{ - Data, - Query, +use actix_web::web::Data; +use chrono::{ + Local, + NaiveDateTime, + TimeZone, }; -use chrono::Local; use maud::{ html, Markup, + PreEscaped, DOCTYPE, }; use sqlx::SqlitePool; #[web::get("/view")] async fn view(data: Data) -> web::Result { - let reminders = sqlx::query_as::<_, (i64, String)>( - r" + let reminders = sqlx::query_as::<_, (NaiveDateTime, String)>( + r#" SELECT - * + date, message FROM - reminders + reminders WHERE - date > ? - ", + date > datetime("now") + ORDER BY date ASC + "#, ) - .bind(Local::now().timestamp() as i64) .fetch_all(&**data) .await - .expect("Failed to fetch reminder."); - println!("{reminders:?}"); + .expect("Failed to fetch reminders."); + + let formatted_reminders: Vec<(String, String)> = reminders + .into_iter() + .map(|(date_time, message)| { + let local_time = Local.from_local_datetime(&date_time).unwrap(); + (local_time.format("%Y/%m/%d %H:%M").to_string(), message) + }) + .collect(); Ok(html! { (DOCTYPE) - ul { - @for reminder in reminders { + style {r#" + body { + font-family: sans; + background-color: #f4f4f4; + margin: 0; + padding: 20px; + } + + ul#reminders { + list-style: none; + padding: 0; + } + + ul#reminders li { + background-color: #fff; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 20px; + margin-bottom: 20px; + } + + ul#reminders li h3 { + margin-bottom: 10px; + font-size: 18px; + color: #333; + } + + ul#reminders li p { + color: #666; + } + "#} + + ul id="reminders" { + @for reminder in formatted_reminders { li { h3 { (reminder.0) } p { (reminder.1) } } } } + + script defer {(PreEscaped(r#" + setInterval(function() { + location.reload(); + }, 5000); + "#))} }) }