feat: initialize thoughts-frontend with Next.js, TypeScript, and ESLint

- Add ESLint configuration for Next.js and TypeScript support.
- Create Next.js configuration file with standalone output option.
- Initialize package.json with scripts for development, build, and linting.
- Set up PostCSS configuration for Tailwind CSS.
- Add SVG assets for UI components.
- Create TypeScript configuration for strict type checking and module resolution.
This commit is contained in:
2025-09-05 17:14:45 +02:00
parent 6bd06ff2c8
commit e5747eaaf3
104 changed files with 7484 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
use axum::{
extract::{Path, Query, State},
http::StatusCode,
response::IntoResponse,
routing::{get, post},
Router,
};
use sea_orm::TryIntoModel;
use app::error::UserError;
use app::persistence::user::{create_user, get_user, search_users};
use app::state::AppState;
use models::params::user::CreateUserParams;
use models::queries::user::UserQuery;
use models::schemas::user::{UserListSchema, UserSchema};
use crate::error::ApiError;
use crate::extractor::{Json, Valid};
use crate::models::{ApiErrorResponse, ParamsErrorResponse};
#[utoipa::path(
post,
path = "",
request_body = CreateUserParams,
responses(
(status = 201, description = "User created", body = UserSchema),
(status = 400, description = "Bad request", body = ApiErrorResponse),
(status = 422, description = "Validation error", body = ParamsErrorResponse),
(status = 500, description = "Internal server error", body = ApiErrorResponse),
)
)]
async fn users_post(
state: State<AppState>,
Valid(Json(params)): Valid<Json<CreateUserParams>>,
) -> Result<impl IntoResponse, ApiError> {
let user = create_user(&state.conn, params)
.await
.map_err(ApiError::from)?;
let user = user.try_into_model().unwrap();
Ok((StatusCode::CREATED, Json(UserSchema::from(user))))
}
#[utoipa::path(
get,
path = "",
params(
UserQuery
),
responses(
(status = 200, description = "List users", body = UserListSchema),
(status = 500, description = "Internal server error", body = ApiErrorResponse),
)
)]
async fn users_get(
state: State<AppState>,
query: Query<UserQuery>,
) -> Result<impl IntoResponse, ApiError> {
let Query(query) = query;
let users = search_users(&state.conn, query)
.await
.map_err(ApiError::from)?;
Ok(Json(UserListSchema::from(users)))
}
#[utoipa::path(
get,
path = "/{id}",
params(
("id" = i32, Path, description = "User id")
),
responses(
(status = 200, description = "Get user", body = UserSchema),
(status = 404, description = "Not found", body = ApiErrorResponse),
(status = 500, description = "Internal server error", body = ApiErrorResponse),
)
)]
async fn users_id_get(
state: State<AppState>,
Path(id): Path<i32>,
) -> Result<impl IntoResponse, ApiError> {
let user = get_user(&state.conn, id).await.map_err(ApiError::from)?;
user.map(|user| Json(UserSchema::from(user)))
.ok_or_else(|| UserError::NotFound.into())
}
pub fn create_user_router() -> Router<AppState> {
Router::new()
.route("/", post(users_post).get(users_get))
.route("/{id}", get(users_id_get))
}