layout improvements
This commit is contained in:
		
							parent
							
								
									f92219f61f
								
							
						
					
					
						commit
						f76999ed2e
					
				@ -39,108 +39,130 @@ const { authenticated, userEmail, userId } = authResult;
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contribution Options -->
 | 
			
		||||
    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 2rem; margin-bottom: 3rem;">
 | 
			
		||||
      
 | 
			
		||||
      <!-- Tools, Methods & Concepts -->
 | 
			
		||||
      <div class="card" style="padding: 2rem; border-left: 4px solid var(--color-primary); cursor: pointer; transition: var(--transition-fast);" onclick="window.location.href='/contribute/tool'">
 | 
			
		||||
        <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
          <div style="width: 48px; height: 48px; background-color: var(--color-primary); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
              <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
 | 
			
		||||
            </svg>
 | 
			
		||||
          </div>
 | 
			
		||||
          <h3 style="margin: 0; color: var(--color-primary); font-size: 1.25rem;">Tools, Methods & Concepts</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <p style="margin-bottom: 1.5rem; line-height: 1.6;">
 | 
			
		||||
          Add new software tools, forensic methodologies, or fundamental concepts to our database. 
 | 
			
		||||
          Includes detailed forms for metadata, licensing, platforms, and categorization.
 | 
			
		||||
<!-- WRAPPER -->
 | 
			
		||||
<div
 | 
			
		||||
  style="
 | 
			
		||||
    display:grid;
 | 
			
		||||
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
 | 
			
		||||
    gap:2rem;
 | 
			
		||||
    align-items:stretch;
 | 
			
		||||
    margin-bottom: 2rem;
 | 
			
		||||
  "
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
  <!-- Tools, Methods & Concepts -->
 | 
			
		||||
  <div class="card" 
 | 
			
		||||
       style="padding: 2rem; border-left: 4px solid var(--color-primary); cursor: pointer; transition: var(--transition-fast);
 | 
			
		||||
              display:flex; flex-direction:column;" 
 | 
			
		||||
       onclick="window.location.href='/contribute/tool'">
 | 
			
		||||
    <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
      <div style="width: 48px; height: 48px; background-color: var(--color-primary); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
          <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </div>
 | 
			
		||||
      <h3 style="margin: 0; color: var(--color-primary); font-size: 1.25rem;">Tools, Methods & Concepts</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <p style="margin-bottom: 1.5rem; line-height: 1.6;">
 | 
			
		||||
      Add new software tools, forensic methodologies, or fundamental concepts to our database. 
 | 
			
		||||
      Includes detailed forms for metadata, licensing, platforms, and categorization.
 | 
			
		||||
    </p>
 | 
			
		||||
    
 | 
			
		||||
    <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
 | 
			
		||||
      <span class="badge" style="background-color: var(--color-primary); color: white;">Software Tools</span>
 | 
			
		||||
      <span class="badge" style="background-color: var(--color-method); color: white;">Methods</span>
 | 
			
		||||
      <span class="badge" style="background-color: var(--color-concept); color: white;">Concepts</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div style="margin-top:auto; display:flex; gap:1rem;">
 | 
			
		||||
      <a href="/contribute/tool" class="btn btn-primary" style="flex: 1;">Add New Entry</a>
 | 
			
		||||
      <a href="/contribute/tool?mode=browse" class="btn btn-secondary" style="flex: 1;">Edit Existing</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <!-- Knowledgebase Articles -->
 | 
			
		||||
  <div class="card" 
 | 
			
		||||
       style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);
 | 
			
		||||
              display:flex; flex-direction:column;" 
 | 
			
		||||
       onclick="window.location.href='/contribute/knowledgebase'">
 | 
			
		||||
    <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
      <div style="width: 48px; height: 48px; background-color: var(--color-accent); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
 | 
			
		||||
          <polyline points="14 2 14 8 20 8"/>
 | 
			
		||||
          <line x1="16" y1="13" x2="8" y2="13"/>
 | 
			
		||||
          <line x1="16" y1="17" x2="8" y2="17"/>
 | 
			
		||||
          <polyline points="10 9 9 9 8 9"/>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </div>
 | 
			
		||||
      <h3 style="margin: 0; color: var(--color-accent); font-size: 1.25rem;">Knowledgebase Articles</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <p style="margin-bottom: 1.5rem; line-height: 1.6;">
 | 
			
		||||
      Write detailed guides, tutorials, configuration instructions, and best practices. 
 | 
			
		||||
      Features a markdown editor with live preview and media upload capabilities.
 | 
			
		||||
    </p>
 | 
			
		||||
    
 | 
			
		||||
    <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
 | 
			
		||||
      <span class="badge badge-secondary">Installation Guides</span>
 | 
			
		||||
      <span class="badge badge-secondary">Tutorials</span>
 | 
			
		||||
      <span class="badge badge-secondary">Best Practices</span>
 | 
			
		||||
      <span class="badge badge-secondary">Case Studies</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div style="margin-top:auto; display:flex; gap:1rem;">
 | 
			
		||||
      <a href="/contribute/knowledgebase" class="btn btn-accent" style="flex: 1;">Write Article</a>
 | 
			
		||||
      <a href="/knowledgebase" class="btn btn-secondary" style="flex: 1;">View Articles</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <!-- Issues & Improvements -->
 | 
			
		||||
  <div class="card" 
 | 
			
		||||
       style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);
 | 
			
		||||
              display:flex; flex-direction:column;">
 | 
			
		||||
    <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
      <div style="width: 48px; height: 48px; background-color: var(--color-warning); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
          <circle cx="12" cy="12" r="10"/>
 | 
			
		||||
          <line x1="12" y1="8" x2="12" y2="12"/>
 | 
			
		||||
          <line x1="12" y1="16" x2="12.01" y2="16"/>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </div>
 | 
			
		||||
      <h3 style="margin: 0; color: var(--color-warning); font-size: 1.25rem;">Issues & Improvements</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div style="display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; align-items: center;">
 | 
			
		||||
      <div style="display:flex; flex-direction:column;">
 | 
			
		||||
        <p style="margin-bottom: 1rem; line-height: 1.6;">
 | 
			
		||||
          Found incorrect information, broken links, or have suggestions for improvements? 
 | 
			
		||||
          Report issues directly in our Git repository or suggest enhancements to existing entries.
 | 
			
		||||
        </p>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-primary); color: white;">Software Tools</span>
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-method); color: white;">Methods</span>
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-concept); color: white;">Concepts</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: flex; gap: 1rem;">
 | 
			
		||||
          <a href="/contribute/tool" class="btn btn-primary" style="flex: 1;">Add New Entry</a>
 | 
			
		||||
          <a href="/contribute/tool?mode=browse" class="btn btn-secondary" style="flex: 1;">Edit Existing</a>
 | 
			
		||||
        <div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-warning); color: white;">Bug Reports</span>
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-warning); color: white;">Corrections</span>
 | 
			
		||||
          <span class="badge" style="background-color: var(--color-warning); color: white;">Suggestions</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <!-- Knowledgebase Articles -->
 | 
			
		||||
      <div class="card" style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);" onclick="window.location.href='/contribute/knowledgebase'">
 | 
			
		||||
        <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
          <div style="width: 48px; height: 48px; background-color: var(--color-accent); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
 | 
			
		||||
              <polyline points="14 2 14 8 20 8"/>
 | 
			
		||||
              <line x1="16" y1="13" x2="8" y2="13"/>
 | 
			
		||||
              <line x1="16" y1="17" x2="8" y2="17"/>
 | 
			
		||||
              <polyline points="10 9 9 9 8 9"/>
 | 
			
		||||
            </svg>
 | 
			
		||||
          </div>
 | 
			
		||||
          <h3 style="margin: 0; color: var(--color-accent); font-size: 1.25rem;">Knowledgebase Articles</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <p style="margin-bottom: 1.5rem; line-height: 1.6;">
 | 
			
		||||
          Write detailed guides, tutorials, configuration instructions, and best practices. 
 | 
			
		||||
          Features a markdown editor with live preview and media upload capabilities.
 | 
			
		||||
        </p>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
 | 
			
		||||
          <span class="badge badge-secondary">Installation Guides</span>
 | 
			
		||||
          <span class="badge badge-secondary">Tutorials</span>
 | 
			
		||||
          <span class="badge badge-secondary">Best Practices</span>
 | 
			
		||||
          <span class="badge badge-secondary">Case Studies</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: flex; gap: 1rem;">
 | 
			
		||||
          <a href="/contribute/knowledgebase" class="btn btn-accent" style="flex: 1;">Write Article</a>
 | 
			
		||||
          <a href="/knowledgebase" class="btn btn-secondary" style="flex: 1;">View Articles</a>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <!-- Issues & Improvements -->
 | 
			
		||||
      <div class="card" style="padding: 2rem; border-left: 4px solid var(--color-warning); grid-column: 1 / -1;">
 | 
			
		||||
        <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
 | 
			
		||||
          <div style="width: 48px; height: 48px; background-color: var(--color-warning); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
 | 
			
		||||
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
 | 
			
		||||
              <circle cx="12" cy="12" r="10"/>
 | 
			
		||||
              <line x1="12" y1="8" x2="12" y2="12"/>
 | 
			
		||||
              <line x1="12" y1="16" x2="12.01" y2="16"/>
 | 
			
		||||
            </svg>
 | 
			
		||||
          </div>
 | 
			
		||||
          <h3 style="margin: 0; color: var(--color-warning); font-size: 1.25rem;">Issues & Improvements</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; align-items: center;">
 | 
			
		||||
          <div>
 | 
			
		||||
            <p style="margin-bottom: 1rem; line-height: 1.6;">
 | 
			
		||||
              Found incorrect information, broken links, or have suggestions for improvements? 
 | 
			
		||||
              Report issues directly in our Git repository or suggest enhancements to existing entries.
 | 
			
		||||
            </p>
 | 
			
		||||
            <div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
 | 
			
		||||
              <span class="badge" style="background-color: var(--color-warning); color: white;">Bug Reports</span>
 | 
			
		||||
              <span class="badge" style="background-color: var(--color-warning); color: white;">Corrections</span>
 | 
			
		||||
              <span class="badge" style="background-color: var(--color-warning); color: white;">Suggestions</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div style="display: flex; flex-direction: column; gap: 1rem;">
 | 
			
		||||
            <a href="https://git.cc24.dev/mstoeck3/cc24-hub/issues/new" target="_blank" rel="noopener noreferrer" class="btn" style="background-color: var(--color-warning); color: white; border-color: var(--color-warning);">
 | 
			
		||||
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
 | 
			
		||||
                <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
 | 
			
		||||
                <polyline points="15 3 21 3 21 9"/>
 | 
			
		||||
                <line x1="10" y1="14" x2="21" y2="3"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
              Report Issue
 | 
			
		||||
            </a>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      <div style="display: flex; flex-direction: column; gap: 1rem;">
 | 
			
		||||
        <a href="https://git.cc24.dev/mstoeck3/cc24-hub/issues/new" target="_blank" rel="noopener noreferrer" class="btn" style="background-color: var(--color-warning); color: white; border-color: var(--color-warning);">
 | 
			
		||||
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
 | 
			
		||||
            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
 | 
			
		||||
            <polyline points="15 3 21 3 21 9"/>
 | 
			
		||||
            <line x1="10" y1="14" x2="21" y2="3"/>
 | 
			
		||||
          </svg>
 | 
			
		||||
          Report Issue
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Push this actions block down if you add more later -->
 | 
			
		||||
    <div style="margin-top:auto;"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <!-- Guidelines -->
 | 
			
		||||
    <div class="card" style="margin-bottom: 2rem;">
 | 
			
		||||
      <h3 style="margin-bottom: 1.5rem; color: var(--color-text);">Contribution Guidelines</h3>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										157
									
								
								src/utils/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/utils/api.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,157 @@
 | 
			
		||||
// src/utils/api.ts
 | 
			
		||||
 | 
			
		||||
// Standard JSON headers for all API responses
 | 
			
		||||
const JSON_HEADERS = {
 | 
			
		||||
  'Content-Type': 'application/json'
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base function to create consistent API responses
 | 
			
		||||
 * All other response helpers use this internally
 | 
			
		||||
 */
 | 
			
		||||
export function createAPIResponse(data: any, status: number = 200, additionalHeaders?: Record<string, string>): Response {
 | 
			
		||||
  const headers = additionalHeaders 
 | 
			
		||||
    ? { ...JSON_HEADERS, ...additionalHeaders }
 | 
			
		||||
    : JSON_HEADERS;
 | 
			
		||||
    
 | 
			
		||||
  return new Response(JSON.stringify(data), {
 | 
			
		||||
    status,
 | 
			
		||||
    headers
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Success responses (2xx status codes)
 | 
			
		||||
 */
 | 
			
		||||
export const apiResponse = {
 | 
			
		||||
  // 200 - Success with data
 | 
			
		||||
  success: (data: any = { success: true }): Response => 
 | 
			
		||||
    createAPIResponse(data, 200),
 | 
			
		||||
  
 | 
			
		||||
  // 201 - Created (for contribution submissions, uploads, etc.)
 | 
			
		||||
  created: (data: any = { success: true }): Response => 
 | 
			
		||||
    createAPIResponse(data, 201),
 | 
			
		||||
    
 | 
			
		||||
  // 202 - Accepted (for async operations)
 | 
			
		||||
  accepted: (data: any = { success: true, message: 'Request accepted for processing' }): Response => 
 | 
			
		||||
    createAPIResponse(data, 202)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Client error responses (4xx status codes)
 | 
			
		||||
 */
 | 
			
		||||
export const apiError = {
 | 
			
		||||
  // 400 - Bad Request
 | 
			
		||||
  badRequest: (message: string = 'Bad request', details?: string[]): Response => 
 | 
			
		||||
    createAPIResponse({ 
 | 
			
		||||
      success: false, 
 | 
			
		||||
      error: message, 
 | 
			
		||||
      ...(details && { details }) 
 | 
			
		||||
    }, 400),
 | 
			
		||||
  
 | 
			
		||||
  // 401 - Unauthorized
 | 
			
		||||
  unauthorized: (message: string = 'Authentication required'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 401),
 | 
			
		||||
  
 | 
			
		||||
  // 403 - Forbidden
 | 
			
		||||
  forbidden: (message: string = 'Access denied'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 403),
 | 
			
		||||
  
 | 
			
		||||
  // 404 - Not Found
 | 
			
		||||
  notFound: (message: string = 'Resource not found'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 404),
 | 
			
		||||
  
 | 
			
		||||
  // 422 - Unprocessable Entity (validation errors)
 | 
			
		||||
  validation: (message: string = 'Validation failed', details?: string[]): Response => 
 | 
			
		||||
    createAPIResponse({ 
 | 
			
		||||
      success: false, 
 | 
			
		||||
      error: message, 
 | 
			
		||||
      ...(details && { details }) 
 | 
			
		||||
    }, 422),
 | 
			
		||||
  
 | 
			
		||||
  // 429 - Rate Limited
 | 
			
		||||
  rateLimit: (message: string = 'Rate limit exceeded. Please wait before trying again.'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 429)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Server error responses (5xx status codes)
 | 
			
		||||
 */
 | 
			
		||||
export const apiServerError = {
 | 
			
		||||
  // 500 - Internal Server Error
 | 
			
		||||
  internal: (message: string = 'Internal server error'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 500),
 | 
			
		||||
  
 | 
			
		||||
  // 502 - Bad Gateway (external service issues)
 | 
			
		||||
  badGateway: (message: string = 'External service error'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 502),
 | 
			
		||||
  
 | 
			
		||||
  // 503 - Service Unavailable
 | 
			
		||||
  unavailable: (message: string = 'Service temporarily unavailable'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 503),
 | 
			
		||||
  
 | 
			
		||||
  // 504 - Gateway Timeout
 | 
			
		||||
  timeout: (message: string = 'Request timeout'): Response => 
 | 
			
		||||
    createAPIResponse({ success: false, error: message }, 504)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Specialized response helpers for common patterns
 | 
			
		||||
 */
 | 
			
		||||
export const apiSpecial = {
 | 
			
		||||
  // JSON parsing error
 | 
			
		||||
  invalidJSON: (): Response => 
 | 
			
		||||
    apiError.badRequest('Invalid JSON in request body'),
 | 
			
		||||
  
 | 
			
		||||
  // Missing required fields
 | 
			
		||||
  missingRequired: (fields: string[]): Response => 
 | 
			
		||||
    apiError.badRequest(`Missing required fields: ${fields.join(', ')}`),
 | 
			
		||||
  
 | 
			
		||||
  // Empty request body
 | 
			
		||||
  emptyBody: (): Response => 
 | 
			
		||||
    apiError.badRequest('Request body cannot be empty'),
 | 
			
		||||
  
 | 
			
		||||
  // File upload responses
 | 
			
		||||
  uploadSuccess: (data: { url: string; filename: string; size: number; storage: string }): Response => 
 | 
			
		||||
    apiResponse.created(data),
 | 
			
		||||
  
 | 
			
		||||
  uploadFailed: (error: string): Response => 
 | 
			
		||||
    apiServerError.internal(`Upload failed: ${error}`),
 | 
			
		||||
  
 | 
			
		||||
  // Contribution responses
 | 
			
		||||
  contributionSuccess: (data: { prUrl?: string; branchName?: string; message: string }): Response => 
 | 
			
		||||
    apiResponse.created({ success: true, ...data }),
 | 
			
		||||
  
 | 
			
		||||
  contributionFailed: (error: string): Response => 
 | 
			
		||||
    apiServerError.internal(`Contribution failed: ${error}`)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const apiWithHeaders = {
 | 
			
		||||
  // Success with custom headers (e.g., Set-Cookie)
 | 
			
		||||
  successWithHeaders: (data: any, headers: Record<string, string>): Response => 
 | 
			
		||||
    createAPIResponse(data, 200, headers),
 | 
			
		||||
  
 | 
			
		||||
  // Redirect response
 | 
			
		||||
  redirect: (location: string, temporary: boolean = true): Response => 
 | 
			
		||||
    new Response(null, {
 | 
			
		||||
      status: temporary ? 302 : 301,
 | 
			
		||||
      headers: { 'Location': location }
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export async function handleAPIRequest<T>(
 | 
			
		||||
  operation: () => Promise<T>,
 | 
			
		||||
  errorMessage: string = 'Request processing failed'
 | 
			
		||||
): Promise<T | Response> {
 | 
			
		||||
  try {
 | 
			
		||||
    return await operation();
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(`API Error: ${errorMessage}:`, error);
 | 
			
		||||
    return apiServerError.internal(errorMessage);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createAuthErrorResponse = apiError.unauthorized;
 | 
			
		||||
export const createBadRequestResponse = apiError.badRequest;
 | 
			
		||||
export const createSuccessResponse = apiResponse.success;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user