This commit is contained in:
natib21
2026-07-17 13:10:27 +00:00
parent 6f126a2345
commit 0d98ccb04b
8 changed files with 151 additions and 82 deletions

View File

@@ -281,9 +281,9 @@ export const TeamMembers = ({
};
const ActionDropdown = ({ employee }: { employee: TeamMemberDto }) => {
const status = getUserStatus(employee);
const isPending = status === "pending";
const isNotInvited = status === "Not Invited";
// getUserStatus only ever yields "accepted" | "pending" — a member with no
// password set is "pending", so anything else has one already.
const isPending = getUserStatus(employee) === "pending";
return (
<DropdownMenu>
@@ -328,8 +328,11 @@ export const TeamMembers = ({
{t("positions.viewPositions")}
</DropdownMenuItem>
{/* Resend/Invite Option */}
{onInviteEmployee && (isPending || isNotInvited) && (
{/* Resend/Invite Option. Offered for accepted members too: the code
this sends lets them set a new password, so for someone who
already has one it is a reset — labelled as such rather than as an
invite, which would misdescribe what the operator is doing. */}
{onInviteEmployee && (
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
@@ -337,7 +340,7 @@ export const TeamMembers = ({
}}
className="cursor-pointer dark:text-gray-200 dark:hover:bg-gray-600">
<RefreshCw className="h-4 w-4 mr-2" />
{isPending ? t("Resend Invite") : t("Send Invite")}
{isPending ? t("Resend Invite") : t("Send Password Reset")}
</DropdownMenuItem>
)}

View File

@@ -213,12 +213,15 @@ const UserManagementTree = () => {
// Handle inviting or resending invitation to employees
const handleInviteEmployee = async (employee: TeamMemberDto) => {
try {
// Show immediate feedback that action is being processed
if (employee.status === "pending") {
toast.loading("Resending verification code...");
} else {
toast.loading("Sending invitation...");
}
// A member who already set a password is being sent a fresh set-password
// code — that is a reset, not an invite, so say so. Keyed off
// hasSetPassword (the same fact the menu label uses) rather than the
// looser `status` field, so the wording cannot disagree with the menu.
const isReset = employee.user.hasSetPassword;
toast.loading(
isReset ? "Sending password reset link..." : "Resending verification code...",
);
await resendVerificationCode({
email: employee.user.email,
phoneNumber: employee.user.phoneNumber,
@@ -229,14 +232,14 @@ const UserManagementTree = () => {
? localizedName(employee.user.name)
: localizedName(employee.user.name) || "User";
if (employee.user.status === "pending") {
toast.success("Verification Code Resent", {
description: `A new verification code has been sent to ${userName}`,
if (isReset) {
toast.success("Password Reset Link Sent", {
description: `${userName} can now set a new password. Any earlier code they had no longer works.`,
duration: 4000,
});
} else {
toast.success("Invitation Sent", {
description: `Invitation sent to ${userName}`,
toast.success("Verification Code Resent", {
description: `A new verification code has been sent to ${userName}`,
duration: 4000,
});
}

View File

@@ -81,12 +81,17 @@ export const OrganizationEmployeeSearch: React.FC<
const handleInviteEmployee = async (employee: TeamMemberDto) => {
const lang = i18n.language;
try {
// Show immediate feedback that action is being processed
if (employee.user.status === "pending") {
toast.loading(t("search.resendingVerification"));
} else {
toast.loading(t("search.sendingInvitation"));
}
// A member who already set a password is being sent a fresh set-password
// code — that is a reset, not an invite. Keyed off hasSetPassword (the
// same fact the menu label uses) rather than the looser `status` field,
// so the wording cannot disagree with the menu the operator clicked.
const isReset = employee.user.hasSetPassword;
toast.loading(
isReset
? t("search.sendingPasswordReset")
: t("search.resendingVerification"),
);
await resendVerificationCode({
email: employee.user.email,
@@ -97,14 +102,14 @@ export const OrganizationEmployeeSearch: React.FC<
const userName =
lang === "en" ? employee.user.name.en : employee.user.name.am;
if (employee.user.status === "pending") {
toast.success(t("search.verificationCodeResent"), {
description: t("search.verificationCodeSentTo", { name: userName }),
if (isReset) {
toast.success(t("search.passwordResetSent"), {
description: t("search.passwordResetSentTo", { name: userName }),
duration: 4000,
});
} else {
toast.success(t("search.invitationSent"), {
description: t("search.invitationSentTo", { name: userName }),
toast.success(t("search.verificationCodeResent"), {
description: t("search.verificationCodeSentTo", { name: userName }),
duration: 4000,
});
}