A social knowledge tool for researchers built on ATProto

feat: add API types and update type usage in create annotation page

+80 -57
+4 -3
src/webapp/app/(authenticated)/annotations/create/page.tsx
··· 5 5 import { useAuth } from "@/hooks/useAuth"; 6 6 import { annotationService } from "@/services/api"; 7 7 import { formatAnnotationValue } from "@/components/annotations/utils/valueFormatters"; 8 + import { Template, TemplateDetail } from "@/types/api"; 8 9 import { Button } from "@/components/ui/button"; 9 10 import { Input } from "@/components/ui/input"; 10 11 import { Label } from "@/components/ui/label"; ··· 31 32 32 33 const [url, setUrl] = useState(""); 33 34 const [selectedTemplateId, setSelectedTemplateId] = useState(""); 34 - const [templates, setTemplates] = useState([]); 35 - const [selectedTemplate, setSelectedTemplate] = useState(null); 36 - const [formValues, setFormValues] = useState({}); 35 + const [templates, setTemplates] = useState<Template[]>([]); 36 + const [selectedTemplate, setSelectedTemplate] = useState<TemplateDetail | null>(null); 37 + const [formValues, setFormValues] = useState<Record<string, string>>({}); 37 38 const [loading, setLoading] = useState(false); 38 39 const [error, setError] = useState(""); 39 40 const [success, setSuccess] = useState(false);
+14 -54
src/webapp/services/api.ts
··· 1 1 /** 2 2 * Client-side API service for making requests to the backend 3 3 */ 4 + import { 5 + Template, 6 + TemplateDetail, 7 + Annotation, 8 + AnnotationDetail, 9 + CreateTemplateResponse, 10 + CreateAnnotationsResponse 11 + } from "@/types/api"; 4 12 5 13 // Get the base URL for API requests from environment variables 6 14 const getApiBaseUrl = (): string => { ··· 262 270 required: boolean; 263 271 }>; 264 272 } 265 - ): Promise<{ templateId: string }> => { 273 + ): Promise<CreateTemplateResponse> => { 266 274 const apiBaseUrl = getApiBaseUrl(); 267 275 return authenticatedRequest( 268 276 `${apiBaseUrl}/api/annotations/templates`, ··· 287 295 note?: string; 288 296 }>; 289 297 } 290 - ): Promise<{ annotationIds: string[] }> => { 298 + ): Promise<CreateAnnotationsResponse> => { 291 299 const apiBaseUrl = getApiBaseUrl(); 292 300 return authenticatedRequest( 293 301 `${apiBaseUrl}/api/annotations/from-template`, ··· 302 310 */ 303 311 getTemplates: async ( 304 312 accessToken: string 305 - ): Promise< 306 - Array<{ 307 - id: string; 308 - name: string; 309 - description: string; 310 - createdAt: string; 311 - fieldCount: number; 312 - }> 313 - > => { 313 + ): Promise<Template[]> => { 314 314 const apiBaseUrl = getApiBaseUrl(); 315 315 return authenticatedRequest( 316 316 `${apiBaseUrl}/api/annotations/templates`, ··· 325 325 getTemplateById: async ( 326 326 accessToken: string, 327 327 templateId: string 328 - ): Promise<{ 329 - id: string; 330 - name: string; 331 - description: string; 332 - fields: Array<{ 333 - id: string; 334 - name: string; 335 - description: string; 336 - definitionType: string; 337 - definition: any; 338 - required: boolean; 339 - }>; 340 - createdAt: string; 341 - curatorId: string; 342 - }> => { 328 + ): Promise<TemplateDetail> => { 343 329 const apiBaseUrl = getApiBaseUrl(); 344 330 return authenticatedRequest( 345 331 `${apiBaseUrl}/api/annotations/templates/${templateId}`, ··· 353 339 */ 354 340 getMyAnnotations: async ( 355 341 accessToken: string 356 - ): Promise< 357 - Array<{ 358 - id: string; 359 - url: string; 360 - fieldName: string; 361 - valueType: string; 362 - valuePreview: string; 363 - createdAt: string; 364 - templateName?: string; 365 - }> 366 - > => { 342 + ): Promise<Annotation[]> => { 367 343 const apiBaseUrl = getApiBaseUrl(); 368 344 return authenticatedRequest( 369 345 `${apiBaseUrl}/api/annotations/my-annotations`, ··· 378 354 getAnnotationById: async ( 379 355 accessToken: string, 380 356 annotationId: string 381 - ): Promise<{ 382 - id: string; 383 - url: string; 384 - fieldName: string; 385 - fieldDescription: string; 386 - valueType: string; 387 - valueData: any; 388 - valuePreview: string; 389 - note?: string; 390 - createdAt: string; 391 - curatorId: string; 392 - templateName?: string; 393 - publishedRecordId?: { 394 - uri: string; 395 - cid: string; 396 - }; 397 - }> => { 357 + ): Promise<AnnotationDetail> => { 398 358 const apiBaseUrl = getApiBaseUrl(); 399 359 return authenticatedRequest( 400 360 `${apiBaseUrl}/api/annotations/${annotationId}`,
+62
src/webapp/types/api.ts
··· 1 + // API response types for reuse across the application 2 + 3 + // Template types 4 + export interface Template { 5 + id: string; 6 + name: string; 7 + description: string; 8 + createdAt: string; 9 + fieldCount: number; 10 + } 11 + 12 + export interface TemplateField { 13 + id: string; 14 + name: string; 15 + description: string; 16 + definitionType: string; 17 + definition: any; 18 + required: boolean; 19 + } 20 + 21 + export interface TemplateDetail extends Omit<Template, 'fieldCount'> { 22 + fields: TemplateField[]; 23 + curatorId: string; 24 + } 25 + 26 + // Annotation types 27 + export interface Annotation { 28 + id: string; 29 + url: string; 30 + fieldName: string; 31 + valueType: string; 32 + valuePreview: string; 33 + createdAt: string; 34 + templateName?: string; 35 + } 36 + 37 + export interface AnnotationDetail { 38 + id: string; 39 + url: string; 40 + fieldName: string; 41 + fieldDescription: string; 42 + valueType: string; 43 + valueData: any; 44 + valuePreview: string; 45 + note?: string; 46 + createdAt: string; 47 + curatorId: string; 48 + templateName?: string; 49 + publishedRecordId?: { 50 + uri: string; 51 + cid: string; 52 + }; 53 + } 54 + 55 + // API response types 56 + export interface CreateTemplateResponse { 57 + templateId: string; 58 + } 59 + 60 + export interface CreateAnnotationsResponse { 61 + annotationIds: string[]; 62 + }