Compare commits
6 Commits
feature/bu
...
sgunter/fe
| Author | SHA1 | Date | |
|---|---|---|---|
| bb4fbc3700 | |||
|
|
35d903e7c8 | ||
|
|
1fffb3c2e7 | ||
|
|
4590a74896 | ||
| 190d1db2fa | |||
|
|
b8a44b45b8 |
@@ -1,3 +1,4 @@
|
|||||||
|
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||||
import ReportIssueMain from '@views/components/ReportIssueMain';
|
import ReportIssueMain from '@views/components/ReportIssueMain';
|
||||||
import SentryProvider from '@views/contexts/SentryContext';
|
import SentryProvider from '@views/contexts/SentryContext';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@@ -5,6 +6,8 @@ import { createRoot } from 'react-dom/client';
|
|||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<SentryProvider fullInit>
|
<SentryProvider fullInit>
|
||||||
|
<ExtensionRoot>
|
||||||
<ReportIssueMain />
|
<ReportIssueMain />
|
||||||
|
</ExtensionRoot>
|
||||||
</SentryProvider>
|
</SentryProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ export interface IOptionsStore {
|
|||||||
|
|
||||||
/** whether the promo should be shown */
|
/** whether the promo should be shown */
|
||||||
showUTDiningPromo: boolean;
|
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<IOptionsStore>({
|
export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||||
@@ -34,6 +40,8 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
|
|||||||
alwaysOpenCalendarInNewTab: false,
|
alwaysOpenCalendarInNewTab: false,
|
||||||
showCalendarSidebar: true,
|
showCalendarSidebar: true,
|
||||||
showUTDiningPromo: true,
|
showUTDiningPromo: true,
|
||||||
|
rememberMyEmail: false,
|
||||||
|
emailAddress: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +58,8 @@ export const initSettings = async () =>
|
|||||||
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
||||||
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
||||||
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
||||||
|
rememberMyEmail: await OptionsStore.get('rememberMyEmail'),
|
||||||
|
emailAddress: await OptionsStore.get('emailAddress'),
|
||||||
}) satisfies IOptionsStore;
|
}) satisfies IOptionsStore;
|
||||||
|
|
||||||
// Clothing retailer right
|
// Clothing retailer right
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'uno.css';
|
import 'uno.css';
|
||||||
|
|
||||||
import { captureFeedback } from '@sentry/react';
|
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 React, { useState } from 'react';
|
||||||
|
|
||||||
import { Button } from './common/Button';
|
import { Button } from './common/Button';
|
||||||
@@ -12,19 +14,57 @@ import Text from './common/Text/Text';
|
|||||||
* @returns The rendered component.
|
* @returns The rendered component.
|
||||||
*/
|
*/
|
||||||
export default function ReportIssueMain(): JSX.Element {
|
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 [feedback, setFeedback] = useState('');
|
||||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||||
|
|
||||||
const submitFeedback = async () => {
|
const submitFeedback = async () => {
|
||||||
if (!email || !feedback) {
|
if (!emailAddress || !feedback) {
|
||||||
throw new Error('Email and feedback are required');
|
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',
|
message: feedback || 'No feedback provided',
|
||||||
email,
|
email: emailAddress,
|
||||||
tags: {
|
tags: {
|
||||||
version: chrome.runtime.getManifest().version,
|
version: chrome.runtime.getManifest().version,
|
||||||
},
|
},
|
||||||
@@ -34,16 +74,14 @@ export default function ReportIssueMain(): JSX.Element {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset form fields and close the dialog
|
// Close the dialog
|
||||||
setEmail('');
|
|
||||||
setFeedback('');
|
|
||||||
setIsSubmitted(true);
|
setIsSubmitted(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isSubmitted) {
|
if (isSubmitted) {
|
||||||
return (
|
return (
|
||||||
<div className='w-80 flex flex-col rounded-lg bg-white p-6 shadow-lg'>
|
<div className='w-92 flex flex-col rounded-lg bg-white p-6 shadow-lg'>
|
||||||
<Text variant='h2' className='mb-4'>
|
<Text variant='h2' className='my-4'>
|
||||||
Thank you
|
Thank you
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant='p' className='mb-6'>
|
<Text variant='p' className='mb-6'>
|
||||||
@@ -56,28 +94,13 @@ export default function ReportIssueMain(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSubmitted) {
|
|
||||||
return (
|
return (
|
||||||
<div className='w-80 bg-white p-6'>
|
<div className='w-92 bg-white p-6'>
|
||||||
<h2 className='mb-4 text-2xl text-orange font-bold'>{`Hook'em Horns!`}</h2>
|
<h2 className='my-4 text-2xl text-ut-burntorange font-bold'>Longhorn Feedback</h2>
|
||||||
<p className='mb-6 text-gray-600'>Your feedback is music to our ears. Thanks for helping us improve!</p>
|
|
||||||
<button
|
|
||||||
className='w-full rounded bg-orange-600 px-4 py-2 text-white font-bold transition duration-300 hover:bg-orange-700'
|
|
||||||
onClick={() => window.close()}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='w-80 bg-white p-6'>
|
|
||||||
<h2 className='mb-4 text-2xl text-ut-burntorange font-bold'>Longhorn Feedback</h2>
|
|
||||||
<p className='mb-4 text-sm text-ut-black'>Help us make UT Registration Plus even better!</p>
|
<p className='mb-4 text-sm text-ut-black'>Help us make UT Registration Plus even better!</p>
|
||||||
|
|
||||||
<form onSubmit={submitFeedback}>
|
<form onSubmit={submitFeedback}>
|
||||||
<div className='mb-4'>
|
<div className='mb-1'>
|
||||||
<label htmlFor='email' className='mb-1 block text-sm text-ut-black font-medium'>
|
<label htmlFor='email' className='mb-1 block text-sm text-ut-black font-medium'>
|
||||||
Your @utexas.edu email
|
Your @utexas.edu email
|
||||||
</label>
|
</label>
|
||||||
@@ -85,8 +108,13 @@ export default function ReportIssueMain(): JSX.Element {
|
|||||||
<input
|
<input
|
||||||
type='email'
|
type='email'
|
||||||
id='email'
|
id='email'
|
||||||
value={email}
|
value={emailAddress}
|
||||||
onChange={e => setEmail(e.target.value)}
|
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'
|
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'
|
placeholder='bevo@utexas.edu'
|
||||||
required
|
required
|
||||||
@@ -94,6 +122,23 @@ export default function ReportIssueMain(): JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className='mb-4'>
|
||||||
|
<label className='mb-1 flex cursor-pointer content-center gap-1.25 text-sm text-ut-black font-medium'>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='cursor-pointer'
|
||||||
|
checked={rememberMyEmail}
|
||||||
|
onChange={e =>
|
||||||
|
setRememberMyEmail({
|
||||||
|
rememberMyEmail: e.target.checked,
|
||||||
|
emailAddress: emailAddress ?? '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>{' '}
|
||||||
|
Remember my email
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
<label htmlFor='feedback' className='mb-1 block text-sm text-ut-black font-medium'>
|
<label htmlFor='feedback' className='mb-1 block text-sm text-ut-black font-medium'>
|
||||||
Your feedback
|
Your feedback
|
||||||
|
|||||||
Reference in New Issue
Block a user