Skip to content

Commit

Permalink
feat/my applications (#1079)
Browse files Browse the repository at this point in the history
  • Loading branch information
emilyjablonski committed Apr 9, 2021
1 parent 8e911ab commit 2800ee3
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 272 deletions.
10 changes: 10 additions & 0 deletions sites/public/cypress/integration/pages/MyApplications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
describe("My applications page", function () {
it("renders the my applications page", function () {
cy.visit("/account/applications")
cy.getByID("email").type("admin@example.com")
cy.getByID("password").type("abcdef")
cy.get("button").contains("Sign In").click()
cy.visit("/account/applications")
cy.contains("My Applications")
})
})
30 changes: 30 additions & 0 deletions sites/public/pages/account/AppStatusItemWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useContext, useEffect, useState } from "react"
import { Application, Listing } from "@bloom-housing/backend-core/types"
import { AppStatusItem, ApiClientContext } from "@bloom-housing/ui-components"

interface AppStatusItemWrapperProps {
application: Application
}

const AppStatusItemWrapper = (props: AppStatusItemWrapperProps) => {
const { listingsService } = useContext(ApiClientContext)
const [listing, setListing] = useState<Listing>()

useEffect(() => {
listingsService
?.retrieve({ listingId: props.application.listing.id })
.then((retrievedListing) => {
setListing(retrievedListing)
})
.catch((err) => console.error(`Error fetching listing: ${err}`))
}, [listingsService, props.application])

return listing ? (
<AppStatusItem application={props.application} listing={listing} key={props.application.id} />
) : (
// Potential for a loading state here
<></>
)
}

export { AppStatusItemWrapper as default, AppStatusItemWrapper }
124 changes: 124 additions & 0 deletions sites/public/pages/account/application.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useEffect, useState, useContext } from "react"
import {
ApiClientContext,
RequireLogin,
t,
UserContext,
FormCard,
dateToString,
} from "@bloom-housing/ui-components"
import Link from "next/link"
import FormSummaryDetails from "../../src/forms/applications/FormSummaryDetails"
import FormsLayout from "../../layouts/forms"
import { Application, Listing } from "@bloom-housing/backend-core/types"
import { useRouter } from "next/router"

export default () => {
const router = useRouter()
const applicationId = router.query.id as string
const { applicationsService, listingsService } = useContext(ApiClientContext)
const { profile } = useContext(UserContext)
const [application, setApplication] = useState<Application>()
const [listing, setListing] = useState<Listing>()
const [unauthorized, setUnauthorized] = useState(false)
const [noApplication, setNoApplication] = useState(false)
useEffect(() => {
if (profile) {
applicationsService
.retrieve({ applicationId })
.then((app) => {
setApplication(app)
listingsService
?.retrieve({ listingId: app.listing.id })
.then((retrievedListing) => {
setListing(retrievedListing)
})
.catch((err) => {
console.error(`Error fetching listing: ${err}`)
})
})
.catch((err) => {
console.error(`Error fetching application: ${err}`)
const { status } = err.response || {}
if (status === 404) {
setNoApplication(true)
}
if (status === 403) {
setUnauthorized(true)
}
})
}
}, [profile, applicationId, applicationsService, listingsService])

return (
<>
<RequireLogin signInPath="/sign-in" signInMessage={t("t.loginIsRequired")}>
<FormsLayout>
{noApplication && (
<FormCard header={t("account.application.error")}>
<p className="field-note mb-5">{t("account.application.noApplicationError")}</p>
<a href={`applications`} className="button is-small">
{t("account.application.return")}
</a>
</FormCard>
)}
{unauthorized && (
<FormCard header={t("account.application.error")}>
<p className="field-note mb-5">{t("account.application.noAccessError")}</p>
<a href={`applications`} className="button is-small">
{t("account.application.return")}
</a>
</FormCard>
)}
{application && (
<>
<FormCard header={t("account.application.confirmation")}>
<div className="py-2">
{listing && (
<Link
href={`listing/id=${listing.id}`}
as={`${origin}/listing/${listing.id}/${listing.urlSlug}`}
>
<a className="lined text-tiny">
{t("application.confirmation.viewOriginalListing")}
</a>
</Link>
)}
</div>
</FormCard>

<FormCard>
<div className="form-card__lead border-b">
<h2 className="form-card__title is-borderless">
{t("application.confirmation.informationSubmittedTitle")}
</h2>
<p className="field-note mt-4 text-center">
{t("application.confirmation.submitted")}
{dateToString(application.submissionDate)}
</p>
</div>
<div className="form-card__group text-center">
<h3 className="form-card__paragraph-title">
{t("application.confirmation.lotteryNumber")}
</h3>

<p className="font-serif text-3xl my-0">{application.id}</p>
</div>

<FormSummaryDetails application={application} />

<div className="form-card__pager hide-for-print">
<div className="form-card__pager-row py-6">
<a href="#" className="lined text-tiny" onClick={() => window.print()}>
{t("application.confirmation.printCopy")}
</a>
</div>
</div>
</FormCard>
</>
)}
</FormsLayout>
</RequireLogin>
</>
)
}
111 changes: 40 additions & 71 deletions sites/public/pages/account/applications.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,56 @@
import React, { useEffect, useState, Fragment } from "react"
import React, { useEffect, useState, Fragment, useContext } from "react"
import Head from "next/head"
import {
AppearanceBorderType,
AppearanceStyleType,
AppStatusItem,
Button,
ApiClientContext,
DashBlock,
DashBlocks,
HeaderBadge,
LinkButton,
MetaTags,
Modal,
RequireLogin,
t,
UserContext,
} from "@bloom-housing/ui-components"
import Layout from "../../layouts/application"
import moment from "moment"
import { Application, ArcherListing } from "@bloom-housing/backend-core/types"
import { PaginatedApplication } from "@bloom-housing/backend-core/types"
import { AppStatusItemWrapper } from "./AppStatusItemWrapper"

export default () => {
const [applications, setApplications] = useState([])
const [deletingApplication, setDeletingApplication] = useState(null)
const listing = Object.assign({}, ArcherListing)
const { applicationsService } = useContext(ApiClientContext)
const { profile } = useContext(UserContext)
const [applications, setApplications] = useState<PaginatedApplication>()
const [error, setError] = useState(null)

useEffect(() => {
// applicationsService.list().then((apps) => {
// setApplications(apps)
// })
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const listing = {} as any
const application = {} as Application
listing.applicationDueDate = moment().add(10, "days").format()
application.listing = listing
// TODO: Fix the types here (and probably this shouldn't come from the frontend anyway)
// application.updatedAt = moment().toDate()
setApplications([application])
}, [])
if (profile) {
applicationsService
.list({ userId: profile.id })
.then((apps) => {
setApplications(apps)
})
.catch((err) => {
console.error(`Error fetching applications: ${err}`)
setError(`${err}`)
})
}
}, [profile, applicationsService])

const noApplicationsSection = () => {
return error ? (
<div className="p-8">
<h2 className="pb-4">{`${t("account.errorFetchingApplications")}`}</h2>
</div>
) : (
<div className="p-8">
<h2 className="pb-4">{t("account.noApplications")}</h2>
<LinkButton href="/listings">{t("listings.browseListings")}</LinkButton>
</div>
)
}

const noApplicationsSection = (
<div className="p-8">
<h2 className="pb-4">It looks like you haven't applied to any listings yet.</h2>
<LinkButton href="/listings">{t("listings.browseListings")}</LinkButton>
</div>
)
const modalActions = [
<Button
styleType={AppearanceStyleType.primary}
onClick={() => {
// applicationsService.delete(deletingApplication.id).then(() => {
const newApplications = [...applications]
const deletedAppIndex = applications.indexOf(deletingApplication, 0)
delete newApplications[deletedAppIndex]
setDeletingApplication(null)
setApplications(newApplications)
// })
}}
>
{t("t.delete")}
</Button>,
<Button
styleType={AppearanceStyleType.secondary}
border={AppearanceBorderType.borderless}
onClick={() => {
setDeletingApplication(null)
}}
>
{t("t.cancel")}
</Button>,
]
return (
<>
<RequireLogin signInPath="/sign-in" signInMessage={t("t.loginIsRequired")}>
<Modal
open={deletingApplication}
title={t("application.deleteThisApplication")}
ariaDescription={t("application.deleteThisApplication")}
actions={modalActions}
hideCloseIcon
/>
<Layout>
<Head>
<title>{t("nav.myApplications")}</title>
Expand All @@ -88,17 +61,13 @@ export default () => {
<DashBlocks>
<DashBlock title={t("account.myApplications")} icon={<HeaderBadge />}>
<Fragment>
{applications.map((application) => (
<AppStatusItem
key={application.id}
status="inProgress"
listing={listing}
application={application}
setDeletingApplication={setDeletingApplication}
/>
))}
{applications.length == 0 && noApplicationsSection}
{applications &&
applications.items.length > 0 &&
applications.items.map((application, index) => (
<AppStatusItemWrapper key={index} application={application} />
))}
</Fragment>
{!applications && noApplicationsSection()}
</DashBlock>
</DashBlocks>
</div>
Expand Down
Loading

0 comments on commit 2800ee3

Please sign in to comment.