use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, PgPool}; use uuid::Uuid; #[derive(Debug, Serialize, Deserialize, FromRow)] pub struct CustomerProfile { pub id: Uuid, pub user_id: Uuid, pub first_name: Option, pub last_name: Option, pub phone: Option, pub city: Option, pub area: Option, pub preferred_professions: Option>, pub active_requirement_count: i32, pub status: String, pub bio: Option, pub custom_data: Option, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Debug, Serialize, Deserialize)] pub struct UpsertCustomerProfilePayload { pub first_name: Option, pub last_name: Option, pub phone: Option, pub city: Option, pub area: Option, pub preferred_professions: Option>, pub bio: Option, pub custom_data: Option, } pub struct CustomerRepository; impl CustomerRepository { pub async fn get_by_user_id( pool: &PgPool, user_id: Uuid, ) -> Result, sqlx::Error> { let profile = sqlx::query_as::<_, CustomerProfile>( r#" SELECT id, user_id, first_name, last_name, phone, city, area, preferred_professions, active_requirement_count, status, bio, custom_data, created_at, updated_at FROM customer_profiles WHERE user_id = $1 "#, ) .bind(user_id) .fetch_optional(pool) .await?; Ok(profile) } pub async fn upsert( pool: &PgPool, user_id: Uuid, payload: UpsertCustomerProfilePayload, ) -> Result { let profile = sqlx::query_as::<_, CustomerProfile>( r#" INSERT INTO customer_profiles ( user_id, first_name, last_name, phone, city, area, preferred_professions, bio, custom_data, status ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'PENDING') ON CONFLICT (user_id) DO UPDATE SET first_name = EXCLUDED.first_name, last_name = EXCLUDED.last_name, phone = EXCLUDED.phone, city = EXCLUDED.city, area = EXCLUDED.area, preferred_professions = EXCLUDED.preferred_professions, bio = EXCLUDED.bio, custom_data = EXCLUDED.custom_data, status = CASE WHEN customer_profiles.status = 'APPROVED' THEN 'APPROVED' ELSE 'PENDING' END, updated_at = NOW() RETURNING id, user_id, first_name, last_name, phone, city, area, preferred_professions, active_requirement_count, status, bio, custom_data, created_at, updated_at "#, ) .bind(user_id) .bind(payload.first_name) .bind(payload.last_name) .bind(payload.phone) .bind(payload.city) .bind(payload.area) .bind(payload.preferred_professions.unwrap_or_default()) .bind(payload.bio) .bind(payload.custom_data) .fetch_one(pool) .await?; Ok(profile) } pub async fn update_active_requirement_count( pool: &PgPool, id: Uuid, delta: i32, ) -> Result<(), sqlx::Error> { sqlx::query( "UPDATE customer_profiles SET active_requirement_count = active_requirement_count + $1 WHERE id = $2", ) .bind(delta) .bind(id) .execute(pool) .await?; Ok(()) } pub async fn submit_for_verification( pool: &PgPool, user_id: Uuid, ) -> Result { let profile = sqlx::query_as::<_, CustomerProfile>( r#" UPDATE customer_profiles SET status = 'PENDING_REVIEW', updated_at = NOW() WHERE user_id = $1 RETURNING id, user_id, first_name, last_name, phone, city, area, preferred_professions, active_requirement_count, status, bio, custom_data, created_at, updated_at "#, ) .bind(user_id) .fetch_one(pool) .await?; Ok(profile) } }