-
Notifications
You must be signed in to change notification settings - Fork 6
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
10 changed files
with
320 additions
and
91 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
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 |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import Icon from "components/Icon"; | ||
import { Arrow, Content } from "components/Tooltip"; | ||
import { useModalContext } from "contexts/ModalContext"; | ||
import { humanize } from "helpers"; | ||
import { useAdminContext } from "pages/Admin/Context"; | ||
import type { EndowmentBalances } from "types/aws"; | ||
import Figure from "./Figure"; | ||
import { MoveFundForm } from "./MoveFundForm"; | ||
import { Movements } from "./Movements"; | ||
import { PayoutHistory } from "./PayoutHistory"; | ||
import { Schedule } from "./Schedule"; | ||
import { monthPeriod } from "./monthPeriod"; | ||
|
||
export function Loaded({ | ||
classes = "", | ||
...props | ||
}: EndowmentBalances & { classes?: string }) { | ||
const { id } = useAdminContext(); | ||
const period = monthPeriod(); | ||
const { showModal } = useModalContext(); | ||
|
||
const mov = props.movementDetails ?? { | ||
"liq-cash": 0, | ||
"liq-lock": 0, | ||
"lock-cash": 0, | ||
}; | ||
|
||
const liqDeductions = Object.entries(mov).reduce( | ||
(sum, [k, v]) => (k.startsWith("liq-") ? sum + v : sum), | ||
0 | ||
); | ||
const lockDeductions = Object.entries(mov).reduce( | ||
(sum, [k, v]) => (k.startsWith("liq-") ? sum + v : sum), | ||
0 | ||
); | ||
|
||
const grantFromBal = Object.entries(mov).reduce( | ||
(sum, [k, v]) => (k.endsWith("-cash") ? sum + v : sum), | ||
0 | ||
); | ||
|
||
return ( | ||
<div className={`${classes} mt-6`}> | ||
<h3 className="uppercase mb-4 font-black">Account Balances</h3> | ||
<div className="grid gap-4 @lg:grid-cols-2"> | ||
<Figure | ||
title="Savings" | ||
tooltip={ | ||
<Content className="bg-navy-d4 text-gray-l4 text-sm max-w-xs p-4 rounded-lg"> | ||
Funds held in Fidelity Government Money Market (SPAXX) consisting | ||
of cash, US Government Securities and Repurchase Agreements | ||
<Arrow /> | ||
</Content> | ||
} | ||
icon={<Icon size={21} type="PiggyBank" strokeWidth={1.5} />} | ||
amount={`$ ${humanize(props.donationsBal - props.payoutsMade, 2)}`} | ||
actions={ | ||
<div className="mt-8 flex justify-end"> | ||
<button | ||
type="button" | ||
onClick={() => | ||
showModal(MoveFundForm, { | ||
type: "liq-cash", | ||
balance: props.donationsBal - liqDeductions, | ||
mov, | ||
endowId: id, | ||
effect: "append", | ||
}) | ||
} | ||
className="text-xs uppercase bg-blue-d1 text-white px-2 py-1 rounded-sm font-heading hover:bg-blue" | ||
> | ||
withdraw | ||
</button> | ||
</div> | ||
} | ||
/> | ||
<Figure | ||
title="Investments" | ||
tooltip={ | ||
<Content className="bg-navy-d4 text-gray-l4 text-sm max-w-xs p-4 rounded-lg shadow-lg"> | ||
<span className="block mb-2"> | ||
Funds invested in a diversified portfolio comprising | ||
</span> | ||
<div> | ||
<p>50% - Domestic and international equities</p> | ||
<p>30% - Fixed income</p> | ||
<p>15% - Crypto</p> | ||
<p>5% - Cash</p> | ||
</div> | ||
<Arrow /> | ||
</Content> | ||
} | ||
icon={<Icon type="Stocks" size={16} />} | ||
amount={`$ ${humanize(props.sustainabilityFundBal, 2)}`} | ||
/> | ||
<Figure | ||
title="Contributions count" | ||
icon={<Icon type="Users" size={17} />} | ||
amount={props.contributionsCount.toString()} | ||
/> | ||
</div> | ||
|
||
<div className="w-full mt-16 h-1.5 bg-gray-l5 rounded-full shadow-inner" /> | ||
|
||
<h3 className="my-4 font-medium flex items-center"> | ||
<span className="text-sm uppercase font-normal">Period</span> | ||
<span className="ml-2 uppercase text-sm"> | ||
{period.from} - {period.to} | ||
</span> | ||
<p className="text-sm text-navy-l3 ml-auto"> | ||
<span>Ends in </span> | ||
<span className="p-1 px-2 bg-navy-d4 text-gray-l4 text-xs rounded ml-1"> | ||
in {period.distance} | ||
</span> | ||
</p> | ||
</h3> | ||
|
||
<Movements {...mov} classes="mt-4" /> | ||
<Schedule | ||
amount={props.payoutsPending} | ||
periodNext={period.next} | ||
periodRemaining={period.distance} | ||
grantFromBal={grantFromBal} | ||
/> | ||
|
||
<div className="w-full mt-16 h-1.5 bg-gray-l5 rounded-full shadow-inner" /> | ||
<PayoutHistory endowId={id} classes="mt-2" /> | ||
</div> | ||
); | ||
} |
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 |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { Field, Input, Label } from "@headlessui/react"; | ||
import { yupResolver } from "@hookform/resolvers/yup"; | ||
import Modal from "components/Modal"; | ||
import { useErrorContext } from "contexts/ErrorContext"; | ||
import { useModalContext } from "contexts/ModalContext"; | ||
import { humanize } from "helpers"; | ||
import { useForm } from "react-hook-form"; | ||
import { schema, stringNumber } from "schemas/shape"; | ||
import { useMoveFundsMutation } from "services/apes"; | ||
import type { BalanceMovement } from "types/aws"; | ||
|
||
interface IMoveFundForm { | ||
effect: "append" | "override"; | ||
type: keyof BalanceMovement; | ||
endowId: number; | ||
balance: number; | ||
mov: BalanceMovement; | ||
} | ||
|
||
export function MoveFundForm(props: IMoveFundForm) { | ||
const [moveFund, { isLoading }] = useMoveFundsMutation(); | ||
const { closeModal } = useModalContext(); | ||
const { handleError } = useErrorContext(); | ||
type FV = { amount: string }; | ||
|
||
const { | ||
handleSubmit, | ||
register, | ||
formState: { errors, isSubmitting }, | ||
} = useForm<FV>({ | ||
defaultValues: { amount: "" }, | ||
resolver: yupResolver( | ||
schema<FV>({ | ||
amount: stringNumber( | ||
(s) => s.required("required"), | ||
(n) => n.positive().max(props.balance, "can't be more than balance") | ||
), | ||
}) | ||
), | ||
}); | ||
|
||
return ( | ||
<Modal | ||
onSubmit={handleSubmit(async (fv) => { | ||
try { | ||
await moveFund({ | ||
endowId: props.endowId, | ||
...props.mov, | ||
[props.type]: props.mov[props.type] + +fv.amount, | ||
}).unwrap(); | ||
closeModal(); | ||
} catch (err) { | ||
handleError(err, { context: "moving funds" }); | ||
} | ||
})} | ||
as="form" | ||
className="fixed-center z-10 grid gap-y-4 text-navy-d4 bg-white sm:w-full w-[90vw] sm:max-w-lg rounded-lg p-6" | ||
> | ||
<p className="flex items-center gap-2"> | ||
<span className="text-navy-l1 text-sm">Available balance</span> | ||
<span className="font-semibold font-heading"> | ||
$ {humanize(props.balance)} | ||
</span> | ||
</p> | ||
<Field className="grid"> | ||
<Label className="font-semibold mb-1"> | ||
Amount <span className="text-red">*</span> | ||
</Label> | ||
<Input | ||
placeholder="e.g. $ 100" | ||
{...register("amount")} | ||
className="px-4 py-3 rounded-lg outline-blue-d1 border border-gray-l3" | ||
/> | ||
<span className="text-red text-xs text-right empty:hidden mt-1"> | ||
{errors.amount?.message} | ||
</span> | ||
</Field> | ||
<button | ||
disabled={isSubmitting || isLoading} | ||
className="bg-blue-d1 hover:bg-blue disabled:bg-gray text-white rounded-full px-4 py-2 font-heading uppercase font-bold" | ||
> | ||
{isLoading ? "Submitting..." : "Submit"} | ||
</button> | ||
</Modal> | ||
); | ||
} |
Oops, something went wrong.