Made it so that students, connected to a corporate, if they change their e-mail, they get unassigned
This commit is contained in:
@@ -22,8 +22,8 @@ interface Props {
|
|||||||
|
|
||||||
export default function Diagnostic({onFinish}: Props) {
|
export default function Diagnostic({onFinish}: Props) {
|
||||||
const [focus, setFocus] = useState<"academic" | "general">();
|
const [focus, setFocus] = useState<"academic" | "general">();
|
||||||
const [levels, setLevels] = useState({reading: -1, listening: -1, writing: -1, speaking: -1});
|
const [levels, setLevels] = useState({reading: -1, listening: -1, writing: -1, speaking: -1, level: 0});
|
||||||
const [desiredLevels, setDesiredLevels] = useState({reading: 9, listening: 9, writing: 9, speaking: 9});
|
const [desiredLevels, setDesiredLevels] = useState({reading: 9, listening: 9, writing: 9, speaking: 9, level: 9});
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export default function Diagnostic({onFinish}: Props) {
|
|||||||
axios
|
axios
|
||||||
.patch("/api/users/update", {
|
.patch("/api/users/update", {
|
||||||
focus,
|
focus,
|
||||||
levels: Object.values(levels).includes(-1) ? {reading: 0, listening: 0, writing: 0, speaking: 0} : levels,
|
levels: Object.values(levels).includes(-1) ? {reading: 0, listening: 0, writing: 0, speaking: 0, level: 0} : levels,
|
||||||
desiredLevels,
|
desiredLevels,
|
||||||
isFirstLogin: false,
|
isFirstLogin: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -191,11 +191,12 @@ export default function StudentDashboard({user}: Props) {
|
|||||||
{module === "listening" && <BsHeadphones className="text-ielts-listening w-4 h-4 md:w-5 md:h-5" />}
|
{module === "listening" && <BsHeadphones className="text-ielts-listening w-4 h-4 md:w-5 md:h-5" />}
|
||||||
{module === "writing" && <BsPen className="text-ielts-writing w-4 h-4 md:w-5 md:h-5" />}
|
{module === "writing" && <BsPen className="text-ielts-writing w-4 h-4 md:w-5 md:h-5" />}
|
||||||
{module === "speaking" && <BsMegaphone className="text-ielts-speaking w-4 h-4 md:w-5 md:h-5" />}
|
{module === "speaking" && <BsMegaphone className="text-ielts-speaking w-4 h-4 md:w-5 md:h-5" />}
|
||||||
|
{module === "level" && <BsClipboard className="text-ielts-level w-4 h-4 md:w-5 md:h-5" />}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between w-full">
|
<div className="flex justify-between w-full">
|
||||||
<span className="font-bold md:font-extrabold text-sm">{capitalize(module)}</span>
|
<span className="font-bold md:font-extrabold text-sm">{capitalize(module)}</span>
|
||||||
<span className="text-sm font-normal text-mti-gray-dim">
|
<span className="text-sm font-normal text-mti-gray-dim">
|
||||||
Level {user.levels[module]} / Level {user.desiredLevels[module]}
|
Level {user.levels[module] || 0} / Level {user.desiredLevels[module] || 9}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import {app, storage} from "@/firebase";
|
|||||||
import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore";
|
import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore";
|
||||||
import {withIronSessionApiRoute} from "iron-session/next";
|
import {withIronSessionApiRoute} from "iron-session/next";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import {sessionOptions} from "@/lib/session";
|
||||||
import {User} from "@/interfaces/user";
|
import {Group, User} from "@/interfaces/user";
|
||||||
import {getDownloadURL, getStorage, ref, uploadBytes} from "firebase/storage";
|
import {getDownloadURL, getStorage, ref, uploadBytes} from "firebase/storage";
|
||||||
import {getAuth, signInWithEmailAndPassword, updateEmail, updatePassword} from "firebase/auth";
|
import {getAuth, signInWithEmailAndPassword, updateEmail, updatePassword} from "firebase/auth";
|
||||||
import {errorMessages} from "@/constants/errors";
|
import {errorMessages} from "@/constants/errors";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import {Payment} from "@/interfaces/paypal";
|
import {Payment} from "@/interfaces/paypal";
|
||||||
import { toFixedNumber } from "@/utils/number";
|
import {toFixedNumber} from "@/utils/number";
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
const auth = getAuth(app);
|
const auth = getAuth(app);
|
||||||
|
|
||||||
@@ -22,10 +22,10 @@ export default withIronSessionApiRoute(handler, sessionOptions);
|
|||||||
// but if it is not inserted as a string, some UI components will not work (Invalid Date)
|
// but if it is not inserted as a string, some UI components will not work (Invalid Date)
|
||||||
const addPaymentRecord = async (data: any) => {
|
const addPaymentRecord = async (data: any) => {
|
||||||
await setDoc(doc(db, "payments", data.id), data);
|
await setDoc(doc(db, "payments", data.id), data);
|
||||||
}
|
};
|
||||||
const managePaymentRecords = async (user: User, userId: string | undefined): Promise<boolean> => {
|
const managePaymentRecords = async (user: User, userId: string | undefined): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
if(user.type === 'corporate' && userId) {
|
if (user.type === "corporate" && userId) {
|
||||||
const shortUID = new ShortUniqueId();
|
const shortUID = new ShortUniqueId();
|
||||||
const data: Payment = {
|
const data: Payment = {
|
||||||
id: shortUID.randomUUID(8),
|
id: shortUID.randomUUID(8),
|
||||||
@@ -40,32 +40,33 @@ const managePaymentRecords = async (user: User, userId: string | undefined): Pro
|
|||||||
};
|
};
|
||||||
|
|
||||||
const corporatePayments = await getDocs(query(collection(db, "payments"), where("corporate", "==", userId)));
|
const corporatePayments = await getDocs(query(collection(db, "payments"), where("corporate", "==", userId)));
|
||||||
if(corporatePayments.docs.length === 0) {
|
if (corporatePayments.docs.length === 0) {
|
||||||
await addPaymentRecord(data);
|
await addPaymentRecord(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPaymentPaidAndExpiring = corporatePayments.docs.filter((doc) => {
|
const hasPaymentPaidAndExpiring = corporatePayments.docs.filter((doc) => {
|
||||||
const data = doc.data();
|
const data = doc.data();
|
||||||
return data.isPaid
|
return (
|
||||||
&& moment().isAfter(moment(user.subscriptionExpirationDate).subtract(30, "days"))
|
data.isPaid &&
|
||||||
&& moment().isBefore(moment(user.subscriptionExpirationDate));
|
moment().isAfter(moment(user.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||||
|
moment().isBefore(moment(user.subscriptionExpirationDate))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(hasPaymentPaidAndExpiring.length > 0) {
|
if (hasPaymentPaidAndExpiring.length > 0) {
|
||||||
await addPaymentRecord(data);
|
await addPaymentRecord(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
// if this process fails it should not stop the rest of the process
|
// if this process fails it should not stop the rest of the process
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
if (!req.session.user) {
|
if (!req.session.user) {
|
||||||
@@ -108,6 +109,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
try {
|
try {
|
||||||
const credential = await signInWithEmailAndPassword(auth, req.session.user.email, updatedUser.password);
|
const credential = await signInWithEmailAndPassword(auth, req.session.user.email, updatedUser.password);
|
||||||
await updateEmail(credential.user, updatedUser.email);
|
await updateEmail(credential.user, updatedUser.email);
|
||||||
|
|
||||||
|
const groups = ((await getDocs(collection(db, "groups"))).docs.map((x) => ({...x.data(), id: x.id})) as Group[]).filter((x) =>
|
||||||
|
x.participants.includes(req.session.user!.id),
|
||||||
|
);
|
||||||
|
|
||||||
|
groups.forEach(async (group) => {
|
||||||
|
await setDoc(
|
||||||
|
doc(db, "groups", group.id),
|
||||||
|
{participants: group.participants.filter((x) => x !== req.session.user!.id)},
|
||||||
|
{merge: true},
|
||||||
|
);
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
res.status(400).json({error: "E002", message: errorMessages.E002});
|
res.status(400).json({error: "E002", message: errorMessages.E002});
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import {shouldRedirectHome} from "@/utils/navigation.disabled";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import {BsCamera, BsCameraFill} from "react-icons/bs";
|
import {BsCamera, BsCameraFill} from "react-icons/bs";
|
||||||
import {USER_TYPE_LABELS} from "@/resources/user";
|
import {USER_TYPE_LABELS} from "@/resources/user";
|
||||||
|
import useGroups from "@/hooks/useGroups";
|
||||||
|
import useUsers from "@/hooks/useUsers";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -52,28 +54,32 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
mutateUser: Function,
|
mutateUser: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
function UserProfile({
|
function UserProfile({user, mutateUser}: Props) {
|
||||||
user,
|
const [bio, setBio] = useState(user.bio || "");
|
||||||
mutateUser,
|
const [name, setName] = useState(user.name || "");
|
||||||
}: Props) {
|
const [email, setEmail] = useState(user.email || "");
|
||||||
const [bio, setBio] = useState(user.bio || '');
|
|
||||||
const [name, setName] = useState(user.name || '');
|
|
||||||
const [email, setEmail] = useState(user.email || '');
|
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [newPassword, setNewPassword] = useState("");
|
const [newPassword, setNewPassword] = useState("");
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [profilePicture, setProfilePicture] = useState(user.profilePicture);
|
const [profilePicture, setProfilePicture] = useState(user.profilePicture);
|
||||||
|
|
||||||
const [country, setCountry] = useState<string>(user.demographicInformation?.country || '');
|
const [country, setCountry] = useState<string>(user.demographicInformation?.country || "");
|
||||||
const [phone, setPhone] = useState<string>(user.demographicInformation?.phone || '');
|
const [phone, setPhone] = useState<string>(user.demographicInformation?.phone || "");
|
||||||
const [gender, setGender] = useState<Gender | undefined>(user.demographicInformation?.gender || undefined);
|
const [gender, setGender] = useState<Gender | undefined>(user.demographicInformation?.gender || undefined);
|
||||||
const [employment, setEmployment] = useState<EmploymentStatus | undefined>(user.type === "corporate" ? undefined : user.demographicInformation?.employment);
|
const [employment, setEmployment] = useState<EmploymentStatus | undefined>(
|
||||||
|
user.type === "corporate" ? undefined : user.demographicInformation?.employment,
|
||||||
|
);
|
||||||
const [position, setPosition] = useState<string | undefined>(user.type === "corporate" ? user.demographicInformation?.position : undefined);
|
const [position, setPosition] = useState<string | undefined>(user.type === "corporate" ? user.demographicInformation?.position : undefined);
|
||||||
const [companyName, setCompanyName] = useState<string | undefined>(user.type === 'agent' ? user.agentInformation?.companyName : undefined);
|
const [companyName, setCompanyName] = useState<string | undefined>(user.type === "agent" ? user.agentInformation?.companyName : undefined);
|
||||||
const [commercialRegistration, setCommercialRegistration] = useState<string | undefined>(user.type === 'agent' ? user.agentInformation?.commercialRegistration : undefined);
|
const [commercialRegistration, setCommercialRegistration] = useState<string | undefined>(
|
||||||
|
user.type === "agent" ? user.agentInformation?.commercialRegistration : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const {groups} = useGroups();
|
||||||
|
const {users} = useUsers();
|
||||||
|
|
||||||
const profilePictureInput = useRef(null);
|
const profilePictureInput = useRef(null);
|
||||||
const expirationDateColor = (date: Date) => {
|
const expirationDateColor = (date: Date) => {
|
||||||
@@ -120,6 +126,19 @@ function UserProfile({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (email !== user?.email) {
|
||||||
|
const userAdmins = groups.filter((x) => x.participants.includes(user.id)).map((x) => x.admin);
|
||||||
|
const message =
|
||||||
|
users.filter((x) => userAdmins.includes(x.id) && x.type === "corporate").length > 0
|
||||||
|
? "If you change your e-mail address, you will lose all benefits from your university/institute. Are you sure you want to continue?"
|
||||||
|
: "Are you sure you want to update your e-mail address?";
|
||||||
|
|
||||||
|
if (!confirm(message)) {
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const request = await axios.post("/api/users/update", {
|
const request = await axios.post("/api/users/update", {
|
||||||
bio,
|
bio,
|
||||||
name,
|
name,
|
||||||
@@ -176,7 +195,7 @@ function UserProfile({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col md:flex-row gap-8 w-full">
|
<div className="flex flex-col md:flex-row gap-8 w-full">
|
||||||
<Input
|
<Input
|
||||||
label="Old Password"
|
label="Current Password"
|
||||||
type="password"
|
type="password"
|
||||||
name="password"
|
name="password"
|
||||||
onChange={(e) => setPassword(e)}
|
onChange={(e) => setPassword(e)}
|
||||||
@@ -358,10 +377,10 @@ function UserProfile({
|
|||||||
</span>
|
</span>
|
||||||
<h6 className="font-normal text-base text-mti-gray-taupe">{USER_TYPE_LABELS[user.type]}</h6>
|
<h6 className="font-normal text-base text-mti-gray-taupe">{USER_TYPE_LABELS[user.type]}</h6>
|
||||||
</div>
|
</div>
|
||||||
{user.type === 'agent' && (
|
{user.type === "agent" && (
|
||||||
<div className="flag items-center h-fit">
|
<div className="flag items-center h-fit">
|
||||||
<img
|
<img
|
||||||
alt={user.demographicInformation?.country.toLowerCase() + '_flag'}
|
alt={user.demographicInformation?.country.toLowerCase() + "_flag"}
|
||||||
src={`https://flagcdn.com/w320/${user.demographicInformation?.country.toLowerCase()}.png`}
|
src={`https://flagcdn.com/w320/${user.demographicInformation?.country.toLowerCase()}.png`}
|
||||||
width="320"
|
width="320"
|
||||||
/>
|
/>
|
||||||
@@ -394,9 +413,8 @@ function UserProfile({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const {user, mutateUser } = useUser({redirectTo: "/login"});
|
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -410,9 +428,7 @@ export default function Home() {
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
{user && <UserProfile user={user} mutateUser={mutateUser} /> }
|
{user && <UserProfile user={user} mutateUser={mutateUser} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user