Merged in feature-payment-block-corporate-update (pull request #9)

Blocked Corporate user update through payment records screen

Approved-by: Tiago Ribeiro
This commit is contained in:
João Ramos
2023-12-26 20:25:46 +00:00
committed by Tiago Ribeiro
3 changed files with 171 additions and 55 deletions

View File

@@ -6,11 +6,15 @@ interface Props {
isChecked: boolean;
onChange: (isChecked: boolean) => void;
children: ReactNode;
disabled?: boolean;
}
export default function Checkbox({isChecked, onChange, children}: Props) {
export default function Checkbox({isChecked, onChange, children, disabled}: Props) {
return (
<div className="flex gap-3 items-center text-mti-gray-dim text-sm cursor-pointer" onClick={() => onChange(!isChecked)}>
<div className="flex gap-3 items-center text-mti-gray-dim text-sm cursor-pointer" onClick={() => {
if(disabled) return;
onChange(!isChecked);
}}>
<input type="checkbox" className="hidden" />
<div
className={clsx(

View File

@@ -36,9 +36,30 @@ interface Props {
onViewStudents?: () => void;
onViewTeachers?: () => void;
onViewCorporate?: () => void;
disabled?: boolean;
}
const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, onViewCorporate}: Props) => {
const USER_STATUS_OPTIONS = [
{
value: 'active',
label: 'Active',
}, {
value: 'disabled',
label: 'Disabled',
}, {
value: 'paymentDue',
label: 'Payment Due',
}
];
const USER_TYPE_OPTIONS = Object.keys(USER_TYPE_LABELS).map((type) => ({
value: type,
label: USER_TYPE_LABELS[type as keyof typeof USER_TYPE_LABELS]
}));
const CURRENCIES_OPTIONS = CURRENCIES.map(({ label, currency}) => ({ value: currency, label }));
const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, onViewCorporate, disabled = false}: Props) => {
const [expiryDate, setExpiryDate] = useState<Date | null | undefined>(user.subscriptionExpirationDate);
const [type, setType] = useState(user.type);
const [status, setStatus] = useState(user.status);
@@ -154,6 +175,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
placeholder="Enter corporate name"
defaultValue={companyName}
required
disabled={disabled}
/>
<Input
label="Commercial Registration"
@@ -163,6 +185,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
placeholder="Enter commercial registration"
defaultValue={commercialRegistration}
required
disabled={disabled}
/>
</div>
<Divider className="w-full !m-0" />
@@ -178,6 +201,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
onChange={setCompanyName}
placeholder="Enter corporate name"
defaultValue={companyName}
disabled={disabled}
/>
<Input
label="Number of Users"
@@ -186,6 +210,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
onChange={(e) => setUserAmount(e ? parseInt(e) : undefined)}
placeholder="Enter number of users"
defaultValue={userAmount}
disabled={disabled}
/>
<Input
label="Monthly Duration"
@@ -194,6 +219,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
onChange={(e) => setMonthlyDuration(e ? parseInt(e) : undefined)}
placeholder="Enter monthly duration"
defaultValue={monthlyDuration}
disabled={disabled}
/>
<div className="flex flex-col gap-3 w-full lg:col-span-2">
<label className="font-normal text-base text-mti-gray-dim">Pricing</label>
@@ -204,17 +230,31 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
type="number"
defaultValue={paymentValue || 0}
className="col-span-3"
disabled={disabled}
/>
<Select
className="px-4 py-4 w-full text-sm font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
options={CURRENCIES_OPTIONS}
value={CURRENCIES_OPTIONS.find((c) => c.value === paymentCurrency)}
onChange={(value) => setPaymentCurrency(value?.value)}
styles={{
control: (styles) => ({
...styles,
paddingLeft: "4px",
border: "none",
outline: "none",
":focus": {
outline: "none",
},
}),
option: (styles, state) => ({
...styles,
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
color: state.isFocused ? "black" : styles.color,
}),
}}
isDisabled={disabled}
/>
<select
defaultValue={paymentCurrency}
onChange={(e) => setPaymentCurrency(e.target.value)}
className="p-6 col-span-2 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer bg-white">
{CURRENCIES.map(({label, currency}) => (
<option value={currency} key={currency}>
{label}
</option>
))}
</select>
</div>
</div>
</div>
@@ -249,6 +289,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
color: state.isFocused ? "black" : styles.color,
}),
}}
isDisabled={disabled}
/>
)}
</div>
@@ -262,6 +303,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
type="number"
defaultValue={commissionValue || 0}
className="col-span-3"
disabled={disabled}
/>
</>
) : (
@@ -316,7 +358,8 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
<label className="font-normal text-base text-mti-gray-dim">Employment Status</label>
<RadioGroup
value={user.demographicInformation?.employment}
className="grid grid-cols-2 items-center gap-4 place-items-center">
className="grid grid-cols-2 items-center gap-4 place-items-center"
disabled={disabled}>
{EMPLOYMENT_STATUS.map(({status, label}) => (
<RadioGroup.Option value={status} key={status}>
{({checked}) => (
@@ -351,7 +394,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
<div className="flex flex-col gap-8 w-full">
<div className="relative flex flex-col gap-3 w-full">
<label className="font-normal text-base text-mti-gray-dim">Gender</label>
<RadioGroup value={user.demographicInformation?.gender} className="flex flex-row gap-4 justify-between">
<RadioGroup
value={user.demographicInformation?.gender}
className="flex flex-row gap-4 justify-between"
disabled={disabled}
>
<RadioGroup.Option value="male">
{({checked}) => (
<span
@@ -401,7 +448,9 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
<label className="font-normal text-base text-mti-gray-dim">Expiry Date</label>
<Checkbox
isChecked={!!expiryDate}
onChange={(checked) => setExpiryDate(checked ? user.subscriptionExpirationDate || new Date() : null)}>
onChange={(checked) => setExpiryDate(checked ? user.subscriptionExpirationDate || new Date() : null)}
disabled={disabled}
>
Enabled
</Checkbox>
</div>
@@ -434,6 +483,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
dateFormat="dd/MM/yyyy"
selected={moment(expiryDate).toDate()}
onChange={(date) => setExpiryDate(date)}
disabled={disabled}
/>
)}
</div>
@@ -445,27 +495,55 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
<div className="flex flex-col md:flex-row gap-8 w-full">
<div className="flex flex-col gap-3 w-full">
<label className="font-normal text-base text-mti-gray-dim">Status</label>
<select
defaultValue={user.status}
onChange={(e) => setStatus(e.target.value as typeof user.status)}
className="p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer bg-white">
<option value="active">Active</option>
<option value="disabled">Disabled</option>
<option value="paymentDue">Payment Due</option>
</select>
<Select
className="px-4 py-4 w-full text-sm font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
options={USER_STATUS_OPTIONS}
value={USER_STATUS_OPTIONS.find((o) => o.value === status)}
onChange={(value) => setStatus(value?.value as typeof user.status)}
styles={{
control: (styles) => ({
...styles,
paddingLeft: "4px",
border: "none",
outline: "none",
":focus": {
outline: "none",
},
}),
option: (styles, state) => ({
...styles,
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
color: state.isFocused ? "black" : styles.color,
}),
}}
isDisabled={disabled}
/>
</div>
<div className="flex flex-col gap-3 w-full">
<label className="font-normal text-base text-mti-gray-dim">Type</label>
<select
defaultValue={user.type}
onChange={(e) => setType(e.target.value as typeof user.type)}
className="p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer bg-white">
{Object.keys(USER_TYPE_LABELS).map((type) => (
<option key={type} value={type}>
{USER_TYPE_LABELS[type as keyof typeof USER_TYPE_LABELS]}
</option>
))}
</select>
<Select
className="px-4 py-4 w-full text-sm font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
options={USER_TYPE_OPTIONS}
value={USER_TYPE_OPTIONS.find((o) => o.value === type)}
onChange={(value) => setType(value?.value as typeof user.type)}
styles={{
control: (styles) => ({
...styles,
paddingLeft: "4px",
border: "none",
outline: "none",
":focus": {
outline: "none",
},
}),
option: (styles, state) => ({
...styles,
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
color: state.isFocused ? "black" : styles.color,
}),
}}
isDisabled={disabled}
/>
</div>
</div>
</>
@@ -494,7 +572,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers,
<Button className="w-full max-w-[200px]" variant="outline" onClick={onClose}>
Close
</Button>
<Button onClick={updateUser} className="w-full max-w-[200px]">
<Button disabled={disabled} onClick={updateUser} className="w-full max-w-[200px]">
Update
</Button>
</div>

View File

@@ -237,7 +237,8 @@ const PaymentCreator = ({onClose, reload, showComission = false}: {onClose: () =
};
export default function PaymentRecord() {
const [selectedUser, setSelectedUser] = useState<User>();
const [selectedCorporateUser, setSelectedCorporateUser] = useState<User>();
const [selectedAgentUser, setSelectedAgentUser] = useState<User>();
const [isCreatingPayment, setIsCreatingPayment] = useState(false);
const [filters, setFilters] = useState<{filter: (p: Payment) => boolean; id: string}[]>([]);
const [displayPayments, setDisplayPayments] = useState<Payment[]>([]);
@@ -437,7 +438,7 @@ export default function PaymentRecord() {
className={clsx(
"underline text-mti-purple-light hover:text-mti-purple-dark transition ease-in-out duration-300 cursor-pointer",
)}
onClick={() => setSelectedUser(user)}>
onClick={() => setSelectedCorporateUser(user)}>
{user?.corporateInformation.companyInformation.name || user?.name}
</div>
);
@@ -463,7 +464,7 @@ export default function PaymentRecord() {
cell: (info) => (
<div
className={clsx("underline text-mti-purple-light hover:text-mti-purple-dark transition ease-in-out duration-300 cursor-pointer")}
onClick={() => setSelectedUser(users.find((x) => x.id === info.row.original.agent))}>
onClick={() => setSelectedAgentUser(users.find((x) => x.id === info.row.original.agent))}>
{(users.find((x) => x.id === info.row.original.agent) as AgentUser)?.name}
</div>
),
@@ -517,6 +518,55 @@ export default function PaymentRecord() {
getCoreRowModel: getCoreRowModel(),
});
const getUserModal = () => {
if(user) {
if(selectedCorporateUser) {
return (
<Modal isOpen={!!selectedCorporateUser} onClose={() => setSelectedCorporateUser(undefined)}>
<>
{selectedCorporateUser && (
<div className="w-full flex flex-col gap-8">
<UserCard
loggedInUser={user}
onClose={(shouldReload) => {
setSelectedCorporateUser(undefined);
if (shouldReload) reload();
}}
user={selectedCorporateUser}
disabled
/>
</div>
)}
</>
</Modal>
);
}
if(selectedAgentUser) {
return (
<Modal isOpen={!!selectedAgentUser} onClose={() => setSelectedAgentUser(undefined)}>
<>
{selectedAgentUser && (
<div className="w-full flex flex-col gap-8">
<UserCard
loggedInUser={user}
onClose={(shouldReload) => {
setSelectedAgentUser(undefined);
if (shouldReload) reload();
}}
user={selectedAgentUser}
/>
</div>
)}
</>
</Modal>
);
}
}
return null;
}
return (
<>
<Head>
@@ -531,23 +581,7 @@ export default function PaymentRecord() {
<ToastContainer />
{user && (
<Layout user={user} className="gap-6">
<Modal isOpen={!!selectedUser} onClose={() => setSelectedUser(undefined)}>
<>
{selectedUser && (
<div className="w-full flex flex-col gap-8">
<UserCard
loggedInUser={user}
onClose={(shouldReload) => {
setSelectedUser(undefined);
if (shouldReload) reload();
}}
user={selectedUser}
/>
</div>
)}
</>
</Modal>
{getUserModal()}
<Modal isOpen={isCreatingPayment} onClose={() => setIsCreatingPayment(false)}>
<PaymentCreator
onClose={() => setIsCreatingPayment(false)}