diff --git a/src/pages/report/index.tsx b/src/pages/report/index.tsx index 8fbe2784..6d5f08d5 100644 --- a/src/pages/report/index.tsx +++ b/src/pages/report/index.tsx @@ -1,3 +1,4 @@ +import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot'; import ReportIssueMain from '@views/components/ReportIssueMain'; import SentryProvider from '@views/contexts/SentryContext'; import React from 'react'; @@ -5,6 +6,8 @@ import { createRoot } from 'react-dom/client'; createRoot(document.getElementById('root')!).render( - + + + ); diff --git a/src/shared/storage/OptionsStore.ts b/src/shared/storage/OptionsStore.ts index 33291ead..907d97c9 100644 --- a/src/shared/storage/OptionsStore.ts +++ b/src/shared/storage/OptionsStore.ts @@ -24,6 +24,12 @@ export interface IOptionsStore { /** whether the promo should be shown */ showUTDiningPromo: boolean; + + /** whether the user's email address should be remembered by the extension */ + rememberMyEmail: boolean; + + /** the user's email address, if set and chosen to be remembered */ + emailAddress: string; } export const OptionsStore = createSyncStore({ @@ -34,6 +40,8 @@ export const OptionsStore = createSyncStore({ alwaysOpenCalendarInNewTab: false, showCalendarSidebar: true, showUTDiningPromo: true, + rememberMyEmail: false, + emailAddress: '', }); /** @@ -50,6 +58,8 @@ export const initSettings = async () => alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'), showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'), showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'), + rememberMyEmail: await OptionsStore.get('rememberMyEmail'), + emailAddress: await OptionsStore.get('emailAddress'), }) satisfies IOptionsStore; // Clothing retailer right diff --git a/src/views/components/ReportIssueMain.tsx b/src/views/components/ReportIssueMain.tsx index c3b90492..6ee668b6 100644 --- a/src/views/components/ReportIssueMain.tsx +++ b/src/views/components/ReportIssueMain.tsx @@ -1,6 +1,8 @@ import 'uno.css'; import { captureFeedback } from '@sentry/react'; +import { OptionsStore } from '@shared/storage/OptionsStore'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import React, { useState } from 'react'; import { Button } from './common/Button'; @@ -12,19 +14,57 @@ import Text from './common/Text/Text'; * @returns The rendered component. */ export default function ReportIssueMain(): JSX.Element { - const [email, setEmail] = useState(''); + const queryClient = useQueryClient(); + + const { data: emailAddress } = useQuery({ + queryKey: ['settings', 'emailAddress'], + queryFn: () => OptionsStore.get('emailAddress'), + staleTime: Infinity, // Prevent loading state on refocus + }); + + const { mutate: setEmailAddress } = useMutation({ + mutationKey: ['settings', 'emailAddress'], + mutationFn: async ({ rememberMyEmail, emailAddress }: { rememberMyEmail: boolean; emailAddress: string }) => { + queryClient.setQueryData(['settings', 'emailAddress'], emailAddress); + if (rememberMyEmail) { + OptionsStore.set('emailAddress', emailAddress); + } + }, + }); + + const { data: rememberMyEmail } = useQuery({ + queryKey: ['settings', 'rememberMyEmail'], + queryFn: () => OptionsStore.get('rememberMyEmail'), + staleTime: Infinity, // Prevent loading state on refocus + }); + + const { mutate: setRememberMyEmail } = useMutation({ + mutationKey: ['settings', 'rememberMyEmail'], + mutationFn: async ({ rememberMyEmail, emailAddress }: { rememberMyEmail: boolean; emailAddress: string }) => { + queryClient.setQueryData(['settings', 'rememberMyEmail'], rememberMyEmail); + OptionsStore.set('rememberMyEmail', rememberMyEmail); + + if (rememberMyEmail) { + OptionsStore.set('emailAddress', emailAddress); + } else { + OptionsStore.set('emailAddress', ''); + } + }, + }); + const [feedback, setFeedback] = useState(''); const [isSubmitted, setIsSubmitted] = useState(false); const submitFeedback = async () => { - if (!email || !feedback) { + if (!emailAddress || !feedback) { throw new Error('Email and feedback are required'); } - // Here you would typically send the feedback to a server - await captureFeedback( + + // Send the feedback to Sentry + captureFeedback( { message: feedback || 'No feedback provided', - email, + email: emailAddress, tags: { version: chrome.runtime.getManifest().version, }, @@ -34,16 +74,14 @@ export default function ReportIssueMain(): JSX.Element { } ); - // Reset form fields and close the dialog - setEmail(''); - setFeedback(''); + // Close the dialog setIsSubmitted(true); }; if (isSubmitted) { return ( - - + + Thank you @@ -56,28 +94,13 @@ export default function ReportIssueMain(): JSX.Element { ); } - if (isSubmitted) { - return ( - - {`Hook'em Horns!`} - Your feedback is music to our ears. Thanks for helping us improve! - window.close()} - > - Close - - - ); - } - return ( - - Longhorn Feedback + + Longhorn Feedback Help us make UT Registration Plus even better! - + Your @utexas.edu email @@ -85,8 +108,13 @@ export default function ReportIssueMain(): JSX.Element { setEmail(e.target.value)} + value={emailAddress} + onChange={e => + setEmailAddress({ + emailAddress: e.target.value, + rememberMyEmail: rememberMyEmail ?? false, + }) + } className='w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-orange-500' placeholder='bevo@utexas.edu' required @@ -94,6 +122,23 @@ export default function ReportIssueMain(): JSX.Element { + + + + setRememberMyEmail({ + rememberMyEmail: e.target.checked, + emailAddress: emailAddress ?? '', + }) + } + />{' '} + Remember my email + + + Your feedback
Your feedback is music to our ears. Thanks for helping us improve!
Help us make UT Registration Plus even better!