-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
78 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,18 +25,30 @@ export interface Invitation { | |
|
||
export type EmailParams = { | ||
to_email: string; | ||
from_email: string; | ||
from_name: string; | ||
}; | ||
|
||
const useReferrals = () => { | ||
/** | ||
* State variables to manage invitations, loading state, and error messages. | ||
*/ | ||
const [invitations, setInvitations] = useState<Invitation[]>([]); | ||
const [loading, setLoading] = useState<boolean>(false); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
/** | ||
* Retrieve the current user's email and session data from Redux (or your global state). | ||
* Adjust according to how you store user data in your application. | ||
*/ | ||
const userEmail = useSelector((state: any) => state.auth.email); | ||
const sessionData = useSelector((state: any) => state.auth.session); | ||
|
||
/** | ||
* Fetches all invitations from the Supabase 'invitations' table filtered by senderId. | ||
* This could be used, for example, to list all invitations sent by the current user. | ||
* | ||
* @param {string} senderId - The ID of the user who sent the invitations. | ||
*/ | ||
const fetchInvitations = async (senderId: string) => { | ||
setLoading(true); | ||
setError(null); | ||
|
@@ -52,6 +64,11 @@ const useReferrals = () => { | |
setLoading(false); | ||
}; | ||
|
||
/** | ||
* Checks whether the current user's email has a pending invitation in the 'invitations' table. | ||
* | ||
* @returns {Promise<boolean>} - Returns true if there is at least one pending invitation for the current user's email, otherwise false. | ||
*/ | ||
const checkIfMyEmailHasPendingInvite = async (): Promise<boolean> => { | ||
setLoading(true); | ||
setError(null); | ||
|
@@ -66,6 +83,13 @@ const useReferrals = () => { | |
return hasPending; | ||
}; | ||
|
||
/** | ||
* Accepts an existing invitation by updating its status from 'pending' to 'accepted'. | ||
* and set the `receiver_id` to the current user's profile ID. | ||
* | ||
* @param {string} invitationId - The ID of the invitation to accept. | ||
* @returns {Promise<Invitation | null>} - Returns the updated invitation if successful, otherwise null. | ||
*/ | ||
const acceptInvitation = async (invitationId: string): Promise<Invitation | null> => { | ||
setLoading(true); | ||
setError(null); | ||
|
@@ -94,6 +118,12 @@ const useReferrals = () => { | |
return data; | ||
}; | ||
|
||
/** | ||
* Checks if there is already an invitation from the current user (userEmail) to the given destinationEmail. | ||
* | ||
* @param {string} destinationEmail - The email to check against the 'destination' field in the database. | ||
* @returns {Promise<boolean>} - Returns true if there is an existing invitation, false otherwise. | ||
*/ | ||
const checkIfInvitationSent = async (destinationEmail: string): Promise<boolean> => { | ||
setLoading(true); | ||
setError(null); | ||
|
@@ -108,6 +138,13 @@ const useReferrals = () => { | |
return exists; | ||
}; | ||
|
||
/** | ||
* Checks if the specified email already has an accepted invitation. | ||
* This is useful to see if the user is already enrolled/registered via invitation. | ||
* | ||
* @param {string} destinationEmail - The email to check. | ||
* @returns {Promise<boolean>} - Returns true if there's an invitation with status 'accepted' for this email, otherwise false. | ||
*/ | ||
const checkIfEmailAlreadyAccepted = async (destinationEmail: string): Promise<boolean> => { | ||
setLoading(true); | ||
setError(null); | ||
|
@@ -122,6 +159,14 @@ const useReferrals = () => { | |
return accepted; | ||
}; | ||
|
||
/** | ||
* Sends a new invitation. Inserts a record into the 'invitations' table in Supabase, | ||
* and then triggers an email using EmailJS. | ||
* | ||
* @param {string} destination - The email address of the invitee. | ||
* @param {any} payload - Additional data you want to attach to the invitation (e.g., sender's profile info). | ||
* @returns {Promise<void>} - Throws an error if something goes wrong. | ||
*/ | ||
const sendInvitation = async (destination: string, payload: any): Promise<void> => { | ||
const { error } = await sendInvitationAction(destination, payload, userEmail, sessionData); | ||
|
||
|
@@ -131,14 +176,23 @@ const useReferrals = () => { | |
} else { | ||
console.log('Invitation stored successfully in Supabase.'); | ||
|
||
// Send the email using EmailJS | ||
await sendEmail({ | ||
to_email: destination, | ||
from_email: userEmail ?? '[email protected]', | ||
from_name: payload?.data?.from?.displayName ?? 'Watchit Web3xAI', | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* ------------------------------------------------------------------ | ||
* Accept or Create an 'accepted' invitation for a given userEmail. | ||
* | ||
* 1) If there's any 'pending' invitation with destination = userEmail, | ||
* accept the first one found. | ||
* 2) Otherwise, create a new invitation record with status = 'accepted'. | ||
* ------------------------------------------------------------------ | ||
*/ | ||
const acceptOrCreateInvitationForUser = async () => { | ||
const { error } = await acceptOrCreateInvitationForUserAction(userEmail, sessionData); | ||
|
||
|
@@ -148,12 +202,12 @@ const useReferrals = () => { | |
}; | ||
|
||
const sendEmail = async (data: EmailParams) => { | ||
const { from_name, from_email, to_email } = data; | ||
const { from_name, to_email } = data; | ||
|
||
const templateParams = { | ||
to_email, | ||
from_name, | ||
from_email, | ||
from_email: GLOBAL_CONSTANTS.SENDER_EMAIL, | ||
}; | ||
|
||
try { | ||
|
@@ -170,6 +224,9 @@ const useReferrals = () => { | |
} | ||
}; | ||
|
||
/** | ||
* Return all state variables and methods so they can be used in any component that imports this hook. | ||
*/ | ||
return { | ||
// State | ||
invitations, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,18 @@ | ||
// DATE IMPORTS | ||
import { formatDistance } from 'date-fns'; | ||
|
||
// @MUI | ||
// MUI IMPORTS | ||
import Typography from '@mui/material/Typography'; | ||
import TableRow from '@mui/material/TableRow'; | ||
import TableCell from '@mui/material/TableCell'; | ||
import ListItemText from '@mui/material/ListItemText'; | ||
|
||
// Project components | ||
import useReferrals, {Invitation} from "@src/hooks/use-referrals.ts"; | ||
import Button from "@mui/material/Button"; | ||
|
||
// LOCAL IMPORTS | ||
import {Invitation} from "@src/hooks/use-referrals.ts"; | ||
import AvatarProfile from "@src/components/avatar/avatar.tsx"; | ||
import {useRouter} from "@src/routes/hooks"; | ||
import {paths} from "@src/routes/paths.ts"; | ||
import {useSelector} from "react-redux"; | ||
import {notifySuccess} from "@notifications/internal-notifications.ts"; | ||
import {SUCCESS} from "@notifications/success.ts"; | ||
|
||
// ---------------------------------------------------------------------- | ||
|
||
|
@@ -32,24 +30,11 @@ const capitalizeFirstLetter = (string: string) => { | |
|
||
export default function ProfileReferralsTableRow({ row, selected }: Props) { | ||
const { destination, status, created_at: date, id, receiver_id } = row; | ||
const sessionData = useSelector((state: any) => state.auth.session); | ||
const userEmail = useSelector((state: any) => state.auth.email); | ||
const router = useRouter(); | ||
const { sendEmail } = useReferrals(); | ||
|
||
// If receiver_id is null, send again; otherwise, view profile as link | ||
const handleClick = () => { | ||
if (receiver_id === null) { | ||
sendEmail({ | ||
from_name: sessionData?.profile?.metadata?.displayName ?? 'Watchit Web3xAI', | ||
to_email: destination, | ||
from_email: userEmail ?? '[email protected]' | ||
}).then((_r) => { | ||
notifySuccess(SUCCESS.INVITATIONS_SUCCESSFULLY); | ||
}) | ||
} else { | ||
router.push(paths.dashboard.user.root(receiver_id)); | ||
} | ||
receiver_id && router.push(paths.dashboard.user.root(receiver_id)); | ||
} | ||
|
||
const dateObject = new Date(date); | ||
|
@@ -77,11 +62,13 @@ export default function ProfileReferralsTableRow({ row, selected }: Props) { | |
</TableCell> | ||
|
||
<TableCell> | ||
<Button variant="outlined" size="small" onClick={handleClick}> | ||
{ | ||
receiver_id === null ? 'Resend' : 'View profile' | ||
} | ||
</Button> | ||
{ | ||
receiver_id ? ( | ||
<Button variant="outlined" size="small" onClick={handleClick}> | ||
View profile | ||
</Button> | ||
) : <></> | ||
} | ||
</TableCell> | ||
</TableRow> | ||
); | ||
|