Compare commits
6 Commits
derek/sett
...
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 SentryProvider from '@views/contexts/SentryContext';
|
||||
import React from 'react';
|
||||
@@ -5,6 +6,8 @@ import { createRoot } from 'react-dom/client';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<SentryProvider fullInit>
|
||||
<ReportIssueMain />
|
||||
<ExtensionRoot>
|
||||
<ReportIssueMain />
|
||||
</ExtensionRoot>
|
||||
</SentryProvider>
|
||||
);
|
||||
|
||||
@@ -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<IOptionsStore>({
|
||||
@@ -34,6 +40,8 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||
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
|
||||
|
||||
@@ -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 (
|
||||
<div className='w-80 flex flex-col rounded-lg bg-white p-6 shadow-lg'>
|
||||
<Text variant='h2' className='mb-4'>
|
||||
<div className='w-92 flex flex-col rounded-lg bg-white p-6 shadow-lg'>
|
||||
<Text variant='h2' className='my-4'>
|
||||
Thank you
|
||||
</Text>
|
||||
<Text variant='p' className='mb-6'>
|
||||
@@ -56,28 +94,13 @@ export default function ReportIssueMain(): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
if (isSubmitted) {
|
||||
return (
|
||||
<div className='w-80 bg-white p-6'>
|
||||
<h2 className='mb-4 text-2xl text-orange font-bold'>{`Hook'em Horns!`}</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>
|
||||
<div className='w-92 bg-white p-6'>
|
||||
<h2 className='my-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>
|
||||
|
||||
<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'>
|
||||
Your @utexas.edu email
|
||||
</label>
|
||||
@@ -85,8 +108,13 @@ export default function ReportIssueMain(): JSX.Element {
|
||||
<input
|
||||
type='email'
|
||||
id='email'
|
||||
value={email}
|
||||
onChange={e => 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 {
|
||||
</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'>
|
||||
<label htmlFor='feedback' className='mb-1 block text-sm text-ut-black font-medium'>
|
||||
Your feedback
|
||||
|
||||
Reference in New Issue
Block a user