Skip to content

Commit

Permalink
chore: contextual create
Browse files Browse the repository at this point in the history
  • Loading branch information
siddhart1o1 committed Jan 7, 2025
1 parent 0d47f59 commit 43e316f
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 55 deletions.
182 changes: 166 additions & 16 deletions apps/admin-panel/app/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ import { CreateCustomerDialog } from "./customers/create"
import { CreateDepositDialog } from "./deposits/create"
import { WithdrawalInitiateDialog } from "./withdrawals/initiate"
import { CreateCreditFacilityDialog } from "./credit-facilities/create"

import { CreditFacilityPartialPaymentDialog } from "./credit-facilities/partial-payment"
import { CreateUserDialog } from "./users/create"
import { CreateTermsTemplateDialog } from "./terms-templates/create"
import { CreateCommitteeDialog } from "./committees/create"
import CustomerSelector from "./customers/selector"

import { CreditFacility, Customer } from "@/lib/graphql/generated"
import { CreditFacilityDisbursalInitiateDialog } from "./disbursals/create"

import { CreditFacility, Customer, CreditFacilityStatus } from "@/lib/graphql/generated"
import { Button } from "@/ui/button"
import {
DropdownMenu,
Expand All @@ -24,18 +28,79 @@ import {
DropdownMenuTrigger,
} from "@/ui/dropdown-menu"

export const PATH_CONFIGS = {
COMMITTEES: "/committees",
COMMITTEE_DETAILS: /^\/committees\/[^/]+/,

CREDIT_FACILITIES: "/credit-facilities",
CREDIT_FACILITY_DETAILS: /^\/credit-facilities\/[^/]+/,

CUSTOMERS: "/customers",
CUSTOMER_DETAILS: /^\/customers\/[^/]+/,

DASHBOARD: "/dashboard",

DEPOSITS: "/deposits",

USERS: "/users",
USER_DETAILS: /^\/users\/[^/]+/,

TERMS_TEMPLATES: "/terms-templates",
TERMS_TEMPLATE_DETAILS: /^\/terms-templates\/[^/]+/,

WITHDRAWALS: "/withdrawals",
WITHDRAW_DETAILS: /^\/withdrawals\/[^/]+/,
}

const showCreateButton = (currentPath: string) => {
const allowedPaths = Object.values(PATH_CONFIGS)
return allowedPaths.some((path) => {
if (typeof path === "string") {
return path === currentPath
} else if (path instanceof RegExp) {
return path.test(currentPath)
}
return false
})
}

const isItemAllowedOnCurrentPath = (
allowedPaths: (string | RegExp)[],
currentPath: string,
) => {
if (currentPath === PATH_CONFIGS.DASHBOARD) return true
return allowedPaths.some((path) => {
if (typeof path === "string") {
return path === currentPath
} else if (path instanceof RegExp) {
return path.test(currentPath)
}
return false
})
}

type MenuItem = {
label: string
onClick: () => void
dataTestId: string
allowedPaths: (string | RegExp)[]
conditions?: () => boolean | undefined
}

const CreateButton = () => {
const [createCustomer, setCreateCustomer] = useState(false)
const [createDeposit, setCreateDeposit] = useState(false)
const [createWithdrawal, setCreateWithdrawal] = useState(false)
const [createFacility, setCreateFacility] = useState(false)
const [initiateDisbursal, setInitiateDisbursal] = useState(false)
const [makePayment, setMakePayment] = useState(false)
const [openCreateUserDialog, setOpenCreateUserDialog] = useState(false)
const [openCreateTermsTemplateDialog, setOpenCreateTermsTemplateDialog] =
useState(false)
const [openCreateCommitteeDialog, setOpenCreateCommitteeDialog] = useState(false)
const [showMenu, setShowMenu] = useState(false)

const { customer, setCustomer } = useCreateContext()
const { customer, facility, setCustomer } = useCreateContext()
const [openCustomerSelector, setOpenCustomerSelector] = useState(false)

const pathName = usePathname()
Expand All @@ -44,14 +109,15 @@ const CreateButton = () => {
if (!userIsInCustomerDetailsPage) setCustomer(null)
}

const menuItems = [
const menuItems: MenuItem[] = [
{
label: "Deposit",
onClick: () => {
if (!customer) setOpenCustomerSelector(true)
setCreateDeposit(true)
},
dataTestId: "create-deposit-button",
allowedPaths: [PATH_CONFIGS.CUSTOMER_DETAILS, PATH_CONFIGS.DEPOSITS],
},
{
label: "Withdrawal",
Expand All @@ -60,35 +126,78 @@ const CreateButton = () => {
setCreateWithdrawal(true)
},
dataTestId: "create-withdrawal-button",
allowedPaths: [
PATH_CONFIGS.CUSTOMER_DETAILS,
PATH_CONFIGS.WITHDRAWALS,
PATH_CONFIGS.WITHDRAW_DETAILS,
],
},
{
label: "Customer",
onClick: () => setCreateCustomer(true),
dataTestIds: "create-customer-button",
dataTestId: "create-customer-button",
allowedPaths: [PATH_CONFIGS.CUSTOMERS, PATH_CONFIGS.CUSTOMER_DETAILS],
},

{
label: "Credit Facility",
onClick: () => {
if (!customer) setOpenCustomerSelector(true)
setCreateFacility(true)
},
dataTestId: "create-credit-facility-button",
allowedPaths: [
PATH_CONFIGS.CUSTOMER_DETAILS,
PATH_CONFIGS.CREDIT_FACILITIES,
PATH_CONFIGS.CREDIT_FACILITY_DETAILS,
],
},
{
label: "Disbursal",
onClick: () => {
if (!facility) {
toast.message("Please select a credit facility first")
return
}
setInitiateDisbursal(true)
},
dataTestId: "initiate-disbursal-button",
allowedPaths: [PATH_CONFIGS.CREDIT_FACILITY_DETAILS],
conditions: () =>
facility?.subjectCanInitiateDisbursal &&
facility?.status === CreditFacilityStatus.Active,
},
{
label: "Payment",
onClick: () => {
if (!facility) {
toast.message("Please select a credit facility first")
return
}
setMakePayment(true)
},
dataTestId: "make-payment-button",
allowedPaths: [PATH_CONFIGS.CREDIT_FACILITY_DETAILS],
conditions: () =>
facility?.subjectCanRecordPayment &&
facility?.status === CreditFacilityStatus.Active,
},
{
label: "User",
onClick: () => setOpenCreateUserDialog(true),
dataTestId: "create-user-button",
allowedPaths: [PATH_CONFIGS.USERS, PATH_CONFIGS.USER_DETAILS],
},
{
label: "Terms Template",
onClick: () => setOpenCreateTermsTemplateDialog(true),
dataTestId: "create-terms-template-button",
allowedPaths: [PATH_CONFIGS.TERMS_TEMPLATES, PATH_CONFIGS.TERMS_TEMPLATE_DETAILS],
},
{
label: "Committee",
onClick: () => setOpenCreateCommitteeDialog(true),
dataTestId: "create-committee-button",
allowedPaths: [PATH_CONFIGS.COMMITTEES, PATH_CONFIGS.COMMITTEE_DETAILS],
},
]

Expand All @@ -99,6 +208,18 @@ const CreateButton = () => {

const decideCreation = () => {
setShowMenu(false)

const allowedItems = menuItems.filter((item) => {
const isAllowedOnPath = isItemAllowedOnCurrentPath(item.allowedPaths, pathName)
const meetsConditions = !item.conditions || item.conditions()
return isAllowedOnPath && meetsConditions
})

if (allowedItems.length === 1) {
allowedItems[0].onClick()
return
}

if (pathName === "/customers") {
setCreateCustomer(true)
} else if (pathName === "/users") {
Expand All @@ -118,11 +239,14 @@ const CreateButton = () => {
setCreateFacility(true)
} else if (pathName === "/disbursals") {
toast.message("Disbursals can be initiated from credit facility page")
} else {
} else if (allowedItems.length > 1) {
setShowMenu(true)
}
}

if (!showCreateButton(pathName))
return <div className="invisible w-[88px] h-[36px]" aria-hidden="true" />

return (
<>
<DropdownMenu
Expand All @@ -139,16 +263,22 @@ const CreateButton = () => {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-36">
{menuItems.map((item) => (
<DropdownMenuItem
data-testid={item.dataTestId}
key={item.label}
onClick={item.onClick}
className="cursor-pointer"
>
{item.label}
</DropdownMenuItem>
))}
{menuItems
.filter(
(item) =>
isItemAllowedOnCurrentPath(item.allowedPaths, pathName) &&
(!item.conditions || item.conditions()),
)
.map((item) => (
<DropdownMenuItem
data-testid={item.dataTestId}
key={item.label}
onClick={item.onClick}
className="cursor-pointer"
>
{item.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>

Expand Down Expand Up @@ -215,6 +345,26 @@ const CreateButton = () => {
/>
</>
)}

{facility && (
<>
<CreditFacilityDisbursalInitiateDialog
creditFacilityId={facility.creditFacilityId}
openDialog={initiateDisbursal}
setOpenDialog={() => {
setInitiateDisbursal(false)
}}
/>

<CreditFacilityPartialPaymentDialog
creditFacilityId={facility.creditFacilityId}
openDialog={makePayment}
setOpenDialog={() => {
setMakePayment(false)
}}
/>
</>
)}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@ import React from "react"

import { CreditFacilityCollateralUpdateDialog } from "../collateral-update"

import { CreditFacilityDisbursalInitiateDialog } from "../../disbursals/create"

import { CreditFacilityPartialPaymentDialog } from "../partial-payment"

import {
ApprovalProcess,
ApprovalProcessStatus,
CreditFacilityStatus,
GetCreditFacilityBasicDetailsQuery,
} from "@/lib/graphql/generated"
import { Button } from "@/ui/button"
Expand All @@ -36,11 +31,9 @@ const CreditFacilityDetailsCard: React.FC<CreditFacilityDetailsProps> = ({
}) => {
const [openCollateralUpdateDialog, setOpenCollateralUpdateDialog] =
React.useState(false)
const [openDisbursalInitiateDialog, setOpenDisbursalInitiateDialog] =
React.useState(false)

const [openApprovalDialog, setOpenApprovalDialog] = React.useState(false)
const [openDenialDialog, setOpenDenialDialog] = React.useState(false)
const [openPartialPaymentDialog, setOpenPartialPaymentDialog] = React.useState(false)

const details: DetailItemProps[] = [
{
Expand Down Expand Up @@ -78,26 +71,6 @@ const CreditFacilityDetailsCard: React.FC<CreditFacilityDetailsProps> = ({
Update Collateral
</Button>
)}
{creditFacilityDetails.subjectCanInitiateDisbursal &&
creditFacilityDetails.status === CreditFacilityStatus.Active && (
<Button
variant="outline"
data-testid="initiate-disbursal-button"
onClick={() => setOpenDisbursalInitiateDialog(true)}
>
Initiate Disbursal
</Button>
)}
{creditFacilityDetails.subjectCanRecordPayment &&
creditFacilityDetails.status === CreditFacilityStatus.Active && (
<Button
variant="outline"
data-testid="make-payment-button"
onClick={() => setOpenPartialPaymentDialog(true)}
>
Make Payment
</Button>
)}
{creditFacilityDetails.approvalProcess.status ===
ApprovalProcessStatus.InProgress &&
creditFacilityDetails.approvalProcess.subjectCanSubmitDecision && (
Expand Down Expand Up @@ -135,16 +108,6 @@ const CreditFacilityDetailsCard: React.FC<CreditFacilityDetailsProps> = ({
openDialog={openCollateralUpdateDialog}
setOpenDialog={setOpenCollateralUpdateDialog}
/>
<CreditFacilityDisbursalInitiateDialog
creditFacilityId={creditFacilityId}
openDialog={openDisbursalInitiateDialog}
setOpenDialog={setOpenDisbursalInitiateDialog}
/>
<CreditFacilityPartialPaymentDialog
creditFacilityId={creditFacilityId}
openDialog={openPartialPaymentDialog}
setOpenDialog={setOpenPartialPaymentDialog}
/>
<ApprovalDialog
approvalProcess={creditFacilityDetails?.approvalProcess as ApprovalProcess}
openApprovalDialog={openApprovalDialog}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useTabNavigation } from "@/hooks/use-tab-navigation"

import {
ApprovalProcessStatus,
CreditFacility,
CreditFacilityStatus,
GetCreditFacilityBasicDetailsDocument,
GetCreditFacilityDisbursalsDocument,
Expand All @@ -19,6 +20,7 @@ import {
useGetCreditFacilityBasicDetailsQuery,
} from "@/lib/graphql/generated"
import { useBreadcrumb } from "@/app/breadcrumb-provider"
import { useCreateContext } from "@/app/create"

gql`
fragment CreditFacilityBasicDetailsFragment on CreditFacility {
Expand Down Expand Up @@ -71,12 +73,18 @@ export default function CreditFacilityLayout({
const { currentTab, handleTabChange } = useTabNavigation(TABS, creditFacilityId)
const { setCustomLinks, resetToDefault } = useBreadcrumb()
const client = useApolloClient()
const { setFacility } = useCreateContext()

const { data, loading, error, refetch } = useGetCreditFacilityBasicDetailsQuery({
variables: { id: creditFacilityId },
fetchPolicy: "cache-and-network",
})

useEffect(() => {
data?.creditFacility && setFacility(data?.creditFacility as CreditFacility)
return () => setFacility(null)
}, [data?.creditFacility, setFacility])

useEffect(() => {
if (
data?.creditFacility?.status === CreditFacilityStatus.PendingApproval &&
Expand Down
Loading

0 comments on commit 43e316f

Please sign in to comment.