feat: Add Step Library API foundation (Phase 1: B.1-B.3, B.7)

Implements foundational types and API clients for Step Library:

Task B.3 - TypeScript Types:
- Created types/step.ts with comprehensive interfaces
- Step, StepListItem, StepCategory types
- StepContent with instructions, help_text, commands
- StepListParams for filtering/sorting
- Rating and Review types
- StepCreate/StepUpdate DTOs

Task B.1 - Steps API Client:
- Created api/steps.ts following existing patterns
- CRUD operations (list, get, create, update, delete)
- Search endpoint with query
- Popular tags endpoint
- Rating/review operations (rate, updateRating, deleteRating, getReviews)

Task B.2 - Step Categories API Client:
- Created api/stepCategories.ts
- List and get operations for categories

Task B.7 - Update API Index:
- Exported stepsApi and stepCategoriesApi
- Available for import from '@/api'

Phase 1 foundation complete. Ready for Phase 2 (UI components).
Build tested successfully.

Related: Issue #10

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-02-03 19:05:05 -05:00
parent f93c8d84df
commit d52bfe2e27
4 changed files with 214 additions and 0 deletions

View File

@@ -6,3 +6,5 @@ export { default as inviteApi } from './invite'
export { default as tagsApi } from './tags'
export { default as categoriesApi } from './categories'
export { default as foldersApi } from './folders'
export { default as stepsApi } from './steps'
export { default as stepCategoriesApi } from './stepCategories'

View File

@@ -0,0 +1,16 @@
import apiClient from './client'
import type { StepCategory } from '@/types/step'
export const stepCategoriesApi = {
async list(): Promise<StepCategory[]> {
const response = await apiClient.get<StepCategory[]>('/step-categories')
return response.data
},
async get(id: string): Promise<StepCategory> {
const response = await apiClient.get<StepCategory>(`/step-categories/${id}`)
return response.data
}
}
export default stepCategoriesApi

72
frontend/src/api/steps.ts Normal file
View File

@@ -0,0 +1,72 @@
import apiClient from './client'
import type {
Step,
StepListItem,
StepCreate,
StepUpdate,
StepListParams,
PopularTag,
RatingCreate,
RatingUpdate,
Rating,
Review
} from '@/types/step'
export const stepsApi = {
async list(params?: StepListParams): Promise<StepListItem[]> {
const response = await apiClient.get<StepListItem[]>('/steps', { params })
return response.data
},
async get(id: string): Promise<Step> {
const response = await apiClient.get<Step>(`/steps/${id}`)
return response.data
},
async create(data: StepCreate): Promise<Step> {
const response = await apiClient.post<Step>('/steps', data)
return response.data
},
async update(id: string, data: StepUpdate): Promise<Step> {
const response = await apiClient.put<Step>(`/steps/${id}`, data)
return response.data
},
async delete(id: string): Promise<void> {
await apiClient.delete(`/steps/${id}`)
},
async search(query: string): Promise<StepListItem[]> {
const response = await apiClient.get<StepListItem[]>('/steps/search', {
params: { q: query }
})
return response.data
},
async getPopularTags(): Promise<PopularTag[]> {
const response = await apiClient.get<PopularTag[]>('/steps/popular-tags')
return response.data
},
async rate(id: string, data: RatingCreate): Promise<Rating> {
const response = await apiClient.post<Rating>(`/steps/${id}/ratings`, data)
return response.data
},
async updateRating(id: string, data: RatingUpdate): Promise<Rating> {
const response = await apiClient.put<Rating>(`/steps/${id}/ratings`, data)
return response.data
},
async deleteRating(id: string): Promise<void> {
await apiClient.delete(`/steps/${id}/ratings`)
},
async getReviews(id: string): Promise<Review[]> {
const response = await apiClient.get<Review[]>(`/steps/${id}/reviews`)
return response.data
}
}
export default stepsApi