/**
* @module Forums
*/
import { HttpClient } from '../../infrastructure/http/HttpClient'
import { globalConfig } from '../config.js'
import { ForumCategory, ForumThread } from './types'
import { PaginatedResponse } from '../api/types'
const baseUrl = `/api/forums`
export interface CreateThreadParams {
title: string
first_post_content: string
brand: string
}
/**
* Creates a new thread under a forum category.
*
* @param {CreateThreadParams} params - The parameters for creating the thread.
* @returns {Promise<ForumThread>} - A promise that resolves to the created thread.
* @throws {HttpError} - If the request fails.
*/
export async function createThread(
categoryId: number,
params: CreateThreadParams
): Promise<ForumThread> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.post<ForumThread>(`${baseUrl}/v1/categories/${categoryId}/threads`, params)
}
export interface UpdateThreadParams {
title: string
brand: string
category_id?: number
}
/**
* Updates an existing thread under a forum category.
*
* @param {number} threadId - The ID of the thread to update.
* @param {UpdateThreadParams} params - The parameters for updating the thread.
* @returns {Promise<ForumThread>} - A promise that resolves to the updated thread.
* @throws {HttpError} - If the request fails.
*/
export async function updateThread(
threadId: number,
params: UpdateThreadParams
): Promise<ForumThread> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.put<ForumThread>(`${baseUrl}/v1/threads/${threadId}`, params)
}
/**
* Follow a thread.
*
* @param {number} threadId - The ID of the thread to follow.
* @param {string} brand - The brand associated with the follow action.
* @return {Promise<void>} - A promise that resolves when the thread is followed.
* @throws {HttpError} - If the request fails.
*/
export async function followThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.put<void>(`${baseUrl}/v1/threads/${threadId}/follow`, { brand })
}
/**
* Unfollow a thread to allow further posts.
*
* @param {number} threadId - The ID of the thread to unfollow.
* @param {string} brand - The brand associated with the unfollow action.
* @return {Promise<void>} - A promise that resolves when the thread is unfollowed.
* @throws {HttpError} - If the request fails.
*/
export async function unfollowThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.delete<void>(`${baseUrl}/v1/threads/${threadId}/follow?brand=${brand}`)
}
/**
* Marks a thread as read for the authenticated user.
*
* @param {number} threadId - The ID of the thread to mark as read.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @return {Promise<void>} - A promise that resolves when the thread is marked as read.
* @throws {HttpError} - If the request fails.
*/
export async function markThreadAsRead(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.put<void>(`${baseUrl}/v1/threads/${threadId}/read?brand=${brand}`, {})
}
/**
* Fetches a single forum thread by ID.
*
* @param {number} threadId - The ID of the thread to fetch.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @returns {Promise<ForumThread>} - A promise that resolves to the forum thread.
* @throws {HttpError} - If the HTTP request fails.
*/
export async function fetchThread(threadId: number, brand: string): Promise<ForumThread> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.get<ForumThread>(`${baseUrl}/v1/threads/${threadId}?brand=${brand}`)
}
export interface FetchThreadParams {
is_followed?: boolean,
page?: number,
limit?: number,
sort?: '-last_post_published_on' | string
}
/**
* Fetches forum threads for the given category.
*
* @param {number} categoryId - The ID of the forum category.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @param {FetchThreadParams} params - Optional additional parameters (e.g., is_followed, sort("last_post_published_on","-last_post_published_on","mine")).
* @returns {Promise<PaginatedResponse<ForumThread>>} - A promise that resolves to a paginated list of forum threads.
* @throws {HttpError} - If the HTTP request fails.
*/
export async function fetchThreads(
categoryId: number,
brand: string,
params: FetchThreadParams = {}
): Promise<PaginatedResponse<ForumThread>> {
const httpClient = new HttpClient(globalConfig.baseUrl)
const queryObj: Record<string, string> = { brand, ...Object.fromEntries(
Object.entries(params).filter(([_, v]) => v !== undefined && v !== null).map(([k, v]) => [k, String(v)])
)}
const query = new URLSearchParams(queryObj).toString()
const url = `${baseUrl}/v1/categories/${categoryId}/threads?${query}`
return httpClient.get<PaginatedResponse<ForumThread>>(url)
}
/**
* Pins a thread to the top of its category.
*
* @param {number} threadId - The ID of the thread to pin.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @return {Promise<void>} - A promise that resolves when the thread is pinned.
* @throws {HttpError} - If the request fails.
*/
export async function pinThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.post<void>(`${baseUrl}/v1/threads/${threadId}/pin`, { brand })
}
/**
* Unpins a thread from the top of its category.
*
* @param {number} threadId - The ID of the thread to unpin.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @return {Promise<void>} - A promise that resolves when the thread is unpinned.
* @throws {HttpError} - If the request fails.
*/
export async function unpinThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.delete<void>(`${baseUrl}/v1/threads/${threadId}/pin?brand=${brand}`)
}
/**
* Locks a thread to prevent further posts.
*
* @param {number} threadId - The ID of the thread to lock.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @return {Promise<void>} - A promise that resolves when the thread is locked.
* @throws {HttpError} - If the request fails.
*/
export async function lockThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.post<void>(`${baseUrl}/v1/threads/${threadId}/lock`, { brand })
}
/**
* Unlock a thread to allow further posts.
*
* @param {number} threadId - The ID of the thread to unlock.
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @return {Promise<void>} - A promise that resolves when the thread is unlocked.
* @throws {HttpError} - If the request fails.
*/
export async function unlockThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.delete<void>(`${baseUrl}/v1/threads/${threadId}/lock?brand=${brand}`)
}
/**
* Fetches followed forum Threads for the given brand and current user.
*
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @returns {Promise<PaginatedResponse<ForumThread>>} - A promise that resolves to the list of forum threads.
* @throws {HttpError} - If the request fails.
*/
export async function fetchFollowedThreads(
brand: string
): Promise<PaginatedResponse<ForumThread>> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.get<PaginatedResponse<ForumThread>>(`${baseUrl}/v1/threads?brand=${brand}`)
}
export interface FetchLatestThreadParams {
page?: number,
limit?: number,
}
/**
* Fetches latest forum Threads for the given brand and not blocked to current user.
*
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
* @param {FetchLatestThreadParams} params - Optional pagination parameters.
* @returns {Promise<PaginatedResponse<ForumThread>>} - A promise that resolves to the list of forum threads.
* @throws {HttpError} - If the request fails.
*/
export async function fetchLatestThreads(
brand: string,
params: FetchLatestThreadParams = {}
): Promise<PaginatedResponse<ForumThread>> {
const httpClient = new HttpClient(globalConfig.baseUrl)
const queryObj: Record<string, string> = { brand, ...Object.fromEntries(
Object.entries(params).filter(([_, v]) => v !== undefined && v !== null).map(([k, v]) => [k, String(v)])
)}
const query = new URLSearchParams(queryObj).toString()
return httpClient.get<PaginatedResponse<ForumThread>>(`${baseUrl}/v1/threads/latest?${query}`)
}
/**
* Delete a thread.
*
* @param {number} threadId - The ID of the thread.
* @param {string} brand - The brand associated with the delete action.
* @return {Promise<void>} - A promise that resolves when the thread is deleted.
* @throws {HttpError} - If the request fails.
*/
export async function deleteThread(threadId: number, brand: string): Promise<void> {
const httpClient = new HttpClient(globalConfig.baseUrl)
return httpClient.delete<void>(`${baseUrl}/v1/threads/${threadId}?brand=${brand}`)
}