Skip to content

Commit

Permalink
add cell for fetching organization reportingPeriods and agencies for …
Browse files Browse the repository at this point in the history
…upload form
  • Loading branch information
dysmento committed Jan 3, 2024
1 parent 1927dbe commit 1578344
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 43 deletions.
6 changes: 6 additions & 0 deletions api/src/graphql/organizations.sdl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ export const schema = gql`
type Organization {
id: Int!
agencies: [Agency]!
users: [User]!
name: String!
reportingPeriods: [ReportingPeriod]!
uploads: [Upload]!
uploadValidations: [UploadValidation]!
subrecipients: [Subrecipient]!
projects: [Project]!
}
type Query {
Expand Down
1 change: 1 addition & 0 deletions api/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const getCurrentUser = async (
console.log(decoded)
return {
id: 1,
organizationId: 1,
email: '[email protected]',
roles: ['admin'],
}
Expand Down
24 changes: 24 additions & 0 deletions api/src/services/organizations/organizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,28 @@ export const Organization: OrganizationRelationResolvers = {
agencies: (_obj, { root }) => {
return db.organization.findUnique({ where: { id: root?.id } }).agencies()
},
users: (_obj, { root }) => {
return db.organization.findUnique({ where: { id: root?.id } }).users()
},
reportingPeriods: (_obj, { root }) => {
return db.organization
.findUnique({ where: { id: root?.id } })
.reportingPeriods()
},
uploads: (_obj, { root }) => {
return db.organization.findUnique({ where: { id: root?.id } }).uploads()
},
uploadValidations: (_obj, { root }) => {
return db.organization
.findUnique({ where: { id: root?.id } })
.uploadValidations()
},
subrecipients: (_obj, { root }) => {
return db.organization
.findUnique({ where: { id: root?.id } })
.subrecipients()
},
projects: (_obj, { root }) => {
return db.organization.findUnique({ where: { id: root?.id } }).projects()
},
}
18 changes: 18 additions & 0 deletions api/types/graphql.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ export type Organization = {
agencies: Array<Maybe<Agency>>;
id: Scalars['Int'];
name: Scalars['String'];
projects: Array<Maybe<Project>>;
reportingPeriods: Array<Maybe<ReportingPeriod>>;
subrecipients: Array<Maybe<Subrecipient>>;
uploadValidations: Array<Maybe<UploadValidation>>;
uploads: Array<Maybe<Upload>>;
users: Array<Maybe<User>>;
};

export type OutputTemplate = {
Expand Down Expand Up @@ -1116,13 +1122,25 @@ export type OrganizationResolvers<ContextType = RedwoodGraphQLContext, ParentTyp
agencies: OptArgsResolverFn<Array<Maybe<ResolversTypes['Agency']>>, ParentType, ContextType>;
id: OptArgsResolverFn<ResolversTypes['Int'], ParentType, ContextType>;
name: OptArgsResolverFn<ResolversTypes['String'], ParentType, ContextType>;
projects: OptArgsResolverFn<Array<Maybe<ResolversTypes['Project']>>, ParentType, ContextType>;
reportingPeriods: OptArgsResolverFn<Array<Maybe<ResolversTypes['ReportingPeriod']>>, ParentType, ContextType>;
subrecipients: OptArgsResolverFn<Array<Maybe<ResolversTypes['Subrecipient']>>, ParentType, ContextType>;
uploadValidations: OptArgsResolverFn<Array<Maybe<ResolversTypes['UploadValidation']>>, ParentType, ContextType>;
uploads: OptArgsResolverFn<Array<Maybe<ResolversTypes['Upload']>>, ParentType, ContextType>;
users: OptArgsResolverFn<Array<Maybe<ResolversTypes['User']>>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type OrganizationRelationResolvers<ContextType = RedwoodGraphQLContext, ParentType extends ResolversParentTypes['Organization'] = ResolversParentTypes['Organization']> = {
agencies?: RequiredResolverFn<Array<Maybe<ResolversTypes['Agency']>>, ParentType, ContextType>;
id?: RequiredResolverFn<ResolversTypes['Int'], ParentType, ContextType>;
name?: RequiredResolverFn<ResolversTypes['String'], ParentType, ContextType>;
projects?: RequiredResolverFn<Array<Maybe<ResolversTypes['Project']>>, ParentType, ContextType>;
reportingPeriods?: RequiredResolverFn<Array<Maybe<ResolversTypes['ReportingPeriod']>>, ParentType, ContextType>;
subrecipients?: RequiredResolverFn<Array<Maybe<ResolversTypes['Subrecipient']>>, ParentType, ContextType>;
uploadValidations?: RequiredResolverFn<Array<Maybe<ResolversTypes['UploadValidation']>>, ParentType, ContextType>;
uploads?: RequiredResolverFn<Array<Maybe<ResolversTypes['Upload']>>, ParentType, ContextType>;
users?: RequiredResolverFn<Array<Maybe<ResolversTypes['User']>>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

Expand Down
8 changes: 8 additions & 0 deletions web/src/components/OrganizationCell/OrganizationCell.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Define your own mock data here:
export const standard = (/* vars, { ctx, req } */) => ({
organization: {
id: 42,
reportingPeriods: [{ id: 1, name: 'Reporting Period 1' }],
agencies: [{ id: 1, name: 'Agency 1' }],
},
})
34 changes: 34 additions & 0 deletions web/src/components/OrganizationCell/OrganizationCell.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Meta, StoryObj } from '@storybook/react'

import { Loading, Empty, Failure, Success } from './OrganizationCell'
import { standard } from './OrganizationCell.mock'

const meta: Meta = {
title: 'Cells/OrganizationCell',
}

export default meta

export const loading: StoryObj<typeof Loading> = {
render: () => {
return Loading ? <Loading /> : <></>
},
}

export const empty: StoryObj<typeof Empty> = {
render: () => {
return Empty ? <Empty /> : <></>
},
}

export const failure: StoryObj<typeof Failure> = {
render: (args) => {
return Failure ? <Failure error={new Error('Oh no')} {...args} /> : <></>
},
}

export const success: StoryObj<typeof Success> = {
render: (args) => {
return Success ? <Success {...standard()} {...args} /> : <></>
},
}
42 changes: 42 additions & 0 deletions web/src/components/OrganizationCell/OrganizationCell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { render } from '@redwoodjs/testing/web'

import { Loading, Empty, Failure } from './OrganizationCell'
// import { standard } from './OrganizationCell.mock'

// Generated boilerplate tests do not account for all circumstances
// and can fail without adjustments, e.g. Float and DateTime types.
// Please refer to the RedwoodJS Testing Docs:
// https://redwoodjs.com/docs/testing#testing-cells
// https://redwoodjs.com/docs/testing#jest-expect-type-considerations

describe('OrganizationCell', () => {
it('renders Loading successfully', () => {
expect(() => {
render(<Loading />)
}).not.toThrow()
})

it('renders Empty successfully', async () => {
expect(() => {
render(<Empty />)
}).not.toThrow()
})

it('renders Failure successfully', async () => {
expect(() => {
render(<Failure error={new Error('Oh no')} />)
}).not.toThrow()
})

// When you're ready to test the actual output of your component render
// you could test that, for example, certain text is present:
//
// 1. import { screen } from '@redwoodjs/testing/web'
// 2. Add test: expect(screen.getByText('Hello, world')).toBeInTheDocument()

// it('renders Success successfully', async () => {
// expect(() => {
// render(<Success organization={standard().organization} />)
// }).not.toThrow()
// })
})
70 changes: 70 additions & 0 deletions web/src/components/OrganizationCell/OrganizationCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type {
FindOrganizationQuery,
FindOrganizationQueryVariables,
} from 'types/graphql'

import { Label, SelectField } from '@redwoodjs/forms'
import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web'

export const QUERY = gql`
query FindOrganizationQuery($id: Int!) {
organization: organization(id: $id) {
id
reportingPeriods {
id
name
}
agencies {
id
name
}
}
}
`

export const Loading = () => <div>Loading...</div>

export const Empty = () => <div>Empty</div>

export const Failure = ({
error,
}: CellFailureProps<FindOrganizationQueryVariables>) => (
<div style={{ color: 'red' }}>Error: {error?.message}</div>
)

export const Success = ({
organization,
}: CellSuccessProps<FindOrganizationQuery, FindOrganizationQueryVariables>) => {
return (
<div>
<Label
name="reportingPeriodId"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Reporting Period
</Label>
<SelectField name="reportingPeriodId">
{organization.reportingPeriods.map((reportingPeriod) => (
<option key={reportingPeriod.id} value={reportingPeriod.id}>
{reportingPeriod.name}
</option>
))}
</SelectField>
<Label
name="agencyId"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Agency Code
</Label>
<SelectField name="agencyId">
{organization.agencies.map((agency) => (
<option key={agency.id} value={agency.id}>
{agency.name}
</option>
))}
</SelectField>
</div>
)
}
8 changes: 7 additions & 1 deletion web/src/components/Upload/NewUpload/NewUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { navigate, routes } from '@redwoodjs/router'
import { useMutation } from '@redwoodjs/web'
import { toast } from '@redwoodjs/web/toast'

import { useAuth } from 'src/auth'
import UploadForm from 'src/components/Upload/UploadForm'

const CREATE_UPLOAD_MUTATION = gql`
Expand All @@ -26,14 +27,19 @@ const NewUpload = () => {
toast.error(error.message)
},
})
const { currentUser } = useAuth()

return (
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">Submit Workbook</h2>
</header>
<div className="rw-segment-main">
<UploadForm loading={loading} error={error} />
<UploadForm
organizationId={currentUser.organizationId}
loading={loading}
error={error}
/>
</div>
</div>
)
Expand Down
64 changes: 22 additions & 42 deletions web/src/components/Upload/UploadForm/UploadForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type { EditUploadById } from 'types/graphql'
import {
Form,
FileField,
SelectField,
// HiddenField,
FormError,
FieldError,
Expand All @@ -18,6 +17,8 @@ import { navigate, routes } from '@redwoodjs/router'
import { useMutation } from '@redwoodjs/web'
import { toast } from '@redwoodjs/web/toast'

import OrganizationCell from 'src/components/OrganizationCell'

const CREATE_UPLOAD = gql`
mutation CreateUploadMutation($input: CreateUploadInput!) {
createUpload(input: $input) {
Expand All @@ -29,6 +30,7 @@ const CREATE_UPLOAD = gql`
// type FormUpload = NonNullable<EditUploadById['upload']>

interface UploadFormProps {
organizationId: number
upload?: EditUploadById['upload']
error: RWGqlError
loading: boolean
Expand Down Expand Up @@ -67,24 +69,25 @@ const UploadForm = (props: UploadFormProps) => {
const res = await create({ variables: { input: uploadInput } })
const formData = new FormData()
formData.append('file', data.file[0])
fetch(res.data?.createUpload?.signedUrl, {
method: 'PUT',
headers: {
'Content-Type': data.file[0].type,
},
body: formData,
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
})
.then((responseData) => {
console.log('File upload successful. Response:', responseData)
})
.catch((error) => {
console.error('Error uploading file:', error)
res.data?.createUpload?.signedUrl &&
fetch(res.data?.createUpload?.signedUrl, {
method: 'PUT',
headers: {
'Content-Type': data.file[0].type,
},
body: formData,
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
})
.then((responseData) => {
console.log('File upload successful. Response:', responseData)
})
.catch((error) => {
console.error('Error uploading file:', error)
})
}

const onReset = () => {
Expand All @@ -101,30 +104,7 @@ const UploadForm = (props: UploadFormProps) => {
listClassName="rw-form-error-list"
/>
{/* <HiddenField name="uploadedBy">1</HiddenField> */}
<Label
name="reportingPeriodId"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Reporting Period
</Label>
<SelectField name="reportingPeriodId">
<option value={1}>23Q3</option>
<option value={2}>23Q4</option>
<option value={3}>24Q1</option>
</SelectField>
<Label
name="agencyId"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Agency Code
</Label>
<SelectField name="agencyId">
<option value={1}>ABC123</option>
<option value={2}>EXT</option>
<option value={3}>MISC</option>
</SelectField>
<OrganizationCell id={props.organizationId} />
<FileField name="file" validation={{ required: true }} />
<FieldError name="file" className="rw-field-error" />
<Label
Expand Down
6 changes: 6 additions & 0 deletions web/types/graphql.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,12 @@ export type Organization = {
agencies: Array<Maybe<Agency>>;
id: Scalars['Int'];
name: Scalars['String'];
projects: Array<Maybe<Project>>;
reportingPeriods: Array<Maybe<ReportingPeriod>>;
subrecipients: Array<Maybe<Subrecipient>>;
uploadValidations: Array<Maybe<UploadValidation>>;
uploads: Array<Maybe<Upload>>;
users: Array<Maybe<User>>;
};

export type OutputTemplate = {
Expand Down

0 comments on commit 1578344

Please sign in to comment.