|
|
@ -1,10 +1,10 @@ |
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
import { httpGet, httpPatch, httpPost } from '../../lib/http'; |
|
|
|
import { httpGet, httpPatch } from '../../lib/http'; |
|
|
|
import { pageProgressMessage } from '../../stores/page'; |
|
|
|
import { pageProgressMessage } from '../../stores/page'; |
|
|
|
import type { TeamMemberDocument } from '../TeamMembers/TeamMembersPage'; |
|
|
|
import type { TeamMemberDocument } from '../TeamMembers/TeamMembersPage'; |
|
|
|
import XIcon from '../../icons/close-dark.svg'; |
|
|
|
import XIcon from '../../icons/close-dark.svg'; |
|
|
|
import AcceptIcon from '../../icons/accept.svg'; |
|
|
|
|
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
|
|
|
|
import { AcceptIcon } from '../ReactIcons/AcceptIcon.tsx'; |
|
|
|
|
|
|
|
|
|
|
|
interface NotificationList extends TeamMemberDocument { |
|
|
|
interface NotificationList extends TeamMemberDocument { |
|
|
|
name: string; |
|
|
|
name: string; |
|
|
@ -18,7 +18,7 @@ export function NotificationPage() { |
|
|
|
|
|
|
|
|
|
|
|
const lostNotifications = async () => { |
|
|
|
const lostNotifications = async () => { |
|
|
|
const { error, response } = await httpGet<NotificationList[]>( |
|
|
|
const { error, response } = await httpGet<NotificationList[]>( |
|
|
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-invitation-list` |
|
|
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-invitation-list`, |
|
|
|
); |
|
|
|
); |
|
|
|
if (error || !response) { |
|
|
|
if (error || !response) { |
|
|
|
toast.error(error?.message || 'Something went wrong'); |
|
|
|
toast.error(error?.message || 'Something went wrong'); |
|
|
@ -28,28 +28,37 @@ export function NotificationPage() { |
|
|
|
setNotifications(response); |
|
|
|
setNotifications(response); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
async function respondInvitation(status: 'accept' | 'reject', inviteId: string) { |
|
|
|
async function respondInvitation( |
|
|
|
|
|
|
|
status: 'accept' | 'reject', |
|
|
|
|
|
|
|
inviteId: string, |
|
|
|
|
|
|
|
) { |
|
|
|
setIsLoading(true); |
|
|
|
setIsLoading(true); |
|
|
|
setError(''); |
|
|
|
setError(''); |
|
|
|
const { response, error } = await httpPatch<{ teamId: string }>( |
|
|
|
const { response, error } = await httpPatch<{ teamId: string }>( |
|
|
|
`${import.meta.env.PUBLIC_API_URL}/v1-respond-invite/${inviteId}`, { |
|
|
|
`${import.meta.env.PUBLIC_API_URL}/v1-respond-invite/${inviteId}`, |
|
|
|
status |
|
|
|
{ |
|
|
|
}); |
|
|
|
status, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
); |
|
|
|
if (error || !response) { |
|
|
|
if (error || !response) { |
|
|
|
setError(error?.message || 'Something went wrong') |
|
|
|
setError(error?.message || 'Something went wrong'); |
|
|
|
setIsLoading(false) |
|
|
|
setIsLoading(false); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (status === 'accept') { |
|
|
|
if (status === 'accept') { |
|
|
|
window.location.href = `/team/progress?t=${response.teamId}`; |
|
|
|
window.location.href = `/team/progress?t=${response.teamId}`; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
window.dispatchEvent(new CustomEvent('refresh-notification', { |
|
|
|
window.dispatchEvent( |
|
|
|
|
|
|
|
new CustomEvent('refresh-notification', { |
|
|
|
detail: { |
|
|
|
detail: { |
|
|
|
count: notifications.length - 1 |
|
|
|
count: notifications.length - 1, |
|
|
|
} |
|
|
|
}, |
|
|
|
})); |
|
|
|
}), |
|
|
|
setNotifications(notifications.filter((notification) => notification._id !== inviteId)); |
|
|
|
); |
|
|
|
|
|
|
|
setNotifications( |
|
|
|
|
|
|
|
notifications.filter((notification) => notification._id !== inviteId), |
|
|
|
|
|
|
|
); |
|
|
|
setIsLoading(false); |
|
|
|
setIsLoading(false); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -66,15 +75,20 @@ export function NotificationPage() { |
|
|
|
<h2 className="text-3xl font-bold sm:text-4xl">Notification</h2> |
|
|
|
<h2 className="text-3xl font-bold sm:text-4xl">Notification</h2> |
|
|
|
<p className="mt-2 text-gray-400">Manage your notifications</p> |
|
|
|
<p className="mt-2 text-gray-400">Manage your notifications</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
{ |
|
|
|
{notifications.length === 0 && ( |
|
|
|
notifications.length === 0 && ( |
|
|
|
<div className="mt-6 flex items-center justify-center"> |
|
|
|
<div className="flex items-center justify-center mt-6"> |
|
|
|
|
|
|
|
<p className="text-gray-400"> |
|
|
|
<p className="text-gray-400"> |
|
|
|
No notifications, you can <a href="/team/new" className="text-blue-500 underline hover:no-underline">create a team</a> and invite your friends to join. |
|
|
|
No notifications, you can{' '} |
|
|
|
|
|
|
|
<a |
|
|
|
|
|
|
|
href="/team/new" |
|
|
|
|
|
|
|
className="text-blue-500 underline hover:no-underline" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
create a team |
|
|
|
|
|
|
|
</a>{' '} |
|
|
|
|
|
|
|
and invite your friends to join. |
|
|
|
</p> |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
)} |
|
|
|
} |
|
|
|
|
|
|
|
<div className="space-y-4"> |
|
|
|
<div className="space-y-4"> |
|
|
|
{notifications.map((notification) => ( |
|
|
|
{notifications.map((notification) => ( |
|
|
|
<div className="flex items-center justify-between rounded-md border p-2"> |
|
|
|
<div className="flex items-center justify-between rounded-md border p-2"> |
|
|
@ -86,16 +100,18 @@ export function NotificationPage() { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div className="flex items-center space-x-2"> |
|
|
|
<div className="flex items-center space-x-2"> |
|
|
|
<button type="button" |
|
|
|
<button |
|
|
|
|
|
|
|
type="button" |
|
|
|
disabled={isLoading} |
|
|
|
disabled={isLoading} |
|
|
|
className="inline-flex border p-1 rounded hover:bg-gray-50 disabled:opacity-75" |
|
|
|
className="inline-flex rounded border p-1 hover:bg-gray-50 disabled:opacity-75" |
|
|
|
onClick={() => respondInvitation('accept', notification?._id!)} |
|
|
|
onClick={() => respondInvitation('accept', notification?._id!)} |
|
|
|
> |
|
|
|
> |
|
|
|
<img src={AcceptIcon.src} className="h-4 w-4" /> |
|
|
|
<AcceptIcon className="h-4 w-4" /> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
<button type="button" |
|
|
|
<button |
|
|
|
|
|
|
|
type="button" |
|
|
|
disabled={isLoading} |
|
|
|
disabled={isLoading} |
|
|
|
className="inline-flex border p-1 rounded hover:bg-gray-50 disabled:opacity-75" |
|
|
|
className="inline-flex rounded border p-1 hover:bg-gray-50 disabled:opacity-75" |
|
|
|
onClick={() => respondInvitation('reject', notification?._id!)} |
|
|
|
onClick={() => respondInvitation('reject', notification?._id!)} |
|
|
|
> |
|
|
|
> |
|
|
|
<img alt={'Close'} src={XIcon.src} className="h-4 w-4" /> |
|
|
|
<img alt={'Close'} src={XIcon.src} className="h-4 w-4" /> |
|
|
|