diff --git a/src/@core/api-client.ts b/src/@core/api-client.ts index cb39353..a1eb58d 100644 --- a/src/@core/api-client.ts +++ b/src/@core/api-client.ts @@ -2,7 +2,7 @@ const API_BASE_URL= process.env.REACT_APP_BACKEND_API_URL; // Custom fetch API client export const apiClient = async (endpoint: string, options: RequestInit = {}): Promise => { - const token = typeof window !== 'undefined' ? localStorage.getItem('collabocate_authToken') : ''; // Get token from localStorage + const token = typeof window !== 'undefined' ? localStorage.getItem('authToken') : ''; // Get token from localStorage const headers: HeadersInit = { 'Content-Type': 'application/json', @@ -16,13 +16,19 @@ export const apiClient = async (endpoint: string, options: RequestInit = {}): headers, }); + const data = await response.json(); + if (!response.ok) { - const errorData = await response.json(); - throw new Error(errorData.message || `Error ${response.status}: ${response.statusText}`); + // 🔥 throw structured error instead of plain Error + throw { + status: response.status, + message: data?.error?.message || response.statusText, + raw: data + }; } // Type casting to ensure that response data is in the expected format - return (await response.json()) as T; + return data as T; } catch (error) { console.log(`API Error [${API_BASE_URL}${endpoint}]:`, error); throw error; diff --git a/src/@core/auth.ts b/src/@core/auth.ts new file mode 100644 index 0000000..bb5fbc6 --- /dev/null +++ b/src/@core/auth.ts @@ -0,0 +1,4 @@ +export const signInWithGithub = async () => { + const githubAuthUrl = `${process.env.REACT_APP_BACKEND_API_URL}/auth/github`; + window.location.href = githubAuthUrl; // Redirect user to github Auth +}; diff --git a/src/@core/submitIssue.ts b/src/@core/submitIssue.ts index b3b2496..f6a00e0 100644 --- a/src/@core/submitIssue.ts +++ b/src/@core/submitIssue.ts @@ -8,4 +8,13 @@ export const submitIssue = async (issueData: Issue_POST_RequestBody): Promise => { + const response = await apiClient('/external/github/issues-unauthenticated', { + method: 'POST', + body: JSON.stringify(issueData) + }); + console.log('Issue submitted successfully:', response); + return response; }; \ No newline at end of file diff --git a/src/components/@hooks_state/useSubmitIssue.ts b/src/components/@hooks_state/useSubmitIssue.ts index c4d6010..dbdebbc 100644 --- a/src/components/@hooks_state/useSubmitIssue.ts +++ b/src/components/@hooks_state/useSubmitIssue.ts @@ -1,26 +1,24 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { createContainer } from 'unstated-next'; -import { submitIssue } from '../../@core/submitIssue'; +import { submitIssue, submitAnonymousIssue } from '../../@core/submitIssue'; import { GitHubIssueTemplateContainer } from './useTemplate'; function useSubmitIssueState (){ - const { issueBody, setIssueBody, issueTitle, setIssueTitle, setDropdownButtonTitle, dropdownButtonText} = GitHubIssueTemplateContainer.useContainer(); - const [toastrMessage, setToastrMessage] = useState<{message: string; issueURL?: string; - issueNumber?: number;} | null>(null); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - const title = issueTitle.trim(); - const body = issueBody.trim(); - - if (!title || !body) { - setToastrMessage({message:'Issue Title and Body cannot be empty.'}); - return; - } - - const data = { title, body }; + const { issueBody, setIssueBody, issueTitle, setIssueTitle, setDropdownButtonTitle, dropdownButtonText } = GitHubIssueTemplateContainer.useContainer(); + const [toastrMessage, setToastrMessage] = useState<{ message: string; issueURL?: string; issueNumber?: number } | null>(null); + const [showButton, setShowButton] = useState(false); + const [showGithubLoginButton, setShowGithubLoginButton] = useState(false); + + + const handleButtonClick = () => { + setShowButton(!showButton); + } + + // Shared submission logic + const handleSubmission = async (data: { title: string; body: string }, isAnonymous: boolean) => { + try { + const response = isAnonymous ? await submitAnonymousIssue(data) : await submitIssue(data); - const response = await submitIssue(data); setIssueTitle(''); setIssueBody(''); setToastrMessage({ @@ -29,11 +27,41 @@ function useSubmitIssueState (){ issueNumber: response.data.number, }); setDropdownButtonTitle(dropdownButtonText); + + return response; + } catch (error: any) { + console.log('Error submitting issue:', error); + if (error?.status === 401) { + setShowGithubLoginButton(true); + setToastrMessage({message: 'Please Login as a GitHub User to submit an issue ticket'}); + } + } }; + // Common validation and submission handler + const validateAndSubmit = async (isAnonymous: boolean) => { + const title = issueTitle.trim(); + const body = issueBody.trim(); + + if (!title || !body) { + setToastrMessage({ message: 'Issue Title and Body cannot be empty.' }); + return; + } + + return handleSubmission({ title, body }, isAnonymous); + }; + // Public handlers + const handleSubmit = () => validateAndSubmit(false); + + const handleSubmitAnonymous = () => validateAndSubmit(true); + return { toastrMessage, handleSubmit, + handleSubmitAnonymous, + handleButtonClick, + showButton, + showGithubLoginButton }; } export const SubmitIssueContainer = createContainer(useSubmitIssueState); \ No newline at end of file diff --git a/src/components/@section_modal/ModalPopup.tsx b/src/components/@section_modal/ModalPopup.tsx index 513a704..e3a5ec4 100644 --- a/src/components/@section_modal/ModalPopup.tsx +++ b/src/components/@section_modal/ModalPopup.tsx @@ -10,7 +10,7 @@ export const ModalPopup: React.FunctionComponent = (props: Moda const { instanceId, updateInstanceId } = GlobalContainer.useContainer(); console.log('ModalPopup instance_id:', instanceId); const { issueBody, setIssueBody, issueTitle, setIssueTitle } = GitHubIssueTemplateContainer.useContainer(); - const { toastrMessage, handleSubmit } = SubmitIssueContainer.useContainer(); + const { toastrMessage, handleSubmit, showButton, handleButtonClick, handleSubmitAnonymous, showGithubLoginButton } = SubmitIssueContainer.useContainer(); return ( <> @@ -26,7 +26,7 @@ export const ModalPopup: React.FunctionComponent = (props: Moda

Collabocate | GitHub Sync

-
+

@@ -42,7 +42,15 @@ export const ModalPopup: React.FunctionComponent = (props: Moda
- + + {showButton && ( +
+ + +
+ )} {toastrMessage && (
{toastrMessage.message}
@@ -58,7 +66,10 @@ export const ModalPopup: React.FunctionComponent = (props: Moda
)} -
+ {showGithubLoginButton && ( + Login with Github + )} + ); diff --git a/src/css/@temporary/bb-modal.css b/src/css/@temporary/bb-modal.css index 5a8052c..ac7690e 100644 --- a/src/css/@temporary/bb-modal.css +++ b/src/css/@temporary/bb-modal.css @@ -69,3 +69,13 @@ padding: 16px 0; border-radius: 10px; } + +.bb-collabocate_margin-vertical { + margin: 12px 0; +} + +.bb-collabocate_github-button { + background: black; + padding: 10px; + color: white +}