diff --git a/api/src/graphql/organizations.sdl.ts b/api/src/graphql/organizations.sdl.ts index b26950cb..6b1f2e78 100644 --- a/api/src/graphql/organizations.sdl.ts +++ b/api/src/graphql/organizations.sdl.ts @@ -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 { diff --git a/api/src/lib/auth.ts b/api/src/lib/auth.ts index 84f3ec3d..a3f239da 100644 --- a/api/src/lib/auth.ts +++ b/api/src/lib/auth.ts @@ -35,6 +35,7 @@ export const getCurrentUser = async ( console.log(decoded) return { id: 1, + organizationId: 1, email: 'email@example.com', roles: ['admin'], } diff --git a/api/src/services/organizations/organizations.ts b/api/src/services/organizations/organizations.ts index fddcc571..0c24917b 100644 --- a/api/src/services/organizations/organizations.ts +++ b/api/src/services/organizations/organizations.ts @@ -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() + }, } diff --git a/api/types/graphql.d.ts b/api/types/graphql.d.ts index cbcde983..da107623 100644 --- a/api/types/graphql.d.ts +++ b/api/types/graphql.d.ts @@ -399,6 +399,12 @@ export type Organization = { agencies: Array>; id: Scalars['Int']; name: Scalars['String']; + projects: Array>; + reportingPeriods: Array>; + subrecipients: Array>; + uploadValidations: Array>; + uploads: Array>; + users: Array>; }; export type OutputTemplate = { @@ -1116,6 +1122,12 @@ export type OrganizationResolvers>, ParentType, ContextType>; id: OptArgsResolverFn; name: OptArgsResolverFn; + projects: OptArgsResolverFn>, ParentType, ContextType>; + reportingPeriods: OptArgsResolverFn>, ParentType, ContextType>; + subrecipients: OptArgsResolverFn>, ParentType, ContextType>; + uploadValidations: OptArgsResolverFn>, ParentType, ContextType>; + uploads: OptArgsResolverFn>, ParentType, ContextType>; + users: OptArgsResolverFn>, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1123,6 +1135,12 @@ export type OrganizationRelationResolvers>, ParentType, ContextType>; id?: RequiredResolverFn; name?: RequiredResolverFn; + projects?: RequiredResolverFn>, ParentType, ContextType>; + reportingPeriods?: RequiredResolverFn>, ParentType, ContextType>; + subrecipients?: RequiredResolverFn>, ParentType, ContextType>; + uploadValidations?: RequiredResolverFn>, ParentType, ContextType>; + uploads?: RequiredResolverFn>, ParentType, ContextType>; + users?: RequiredResolverFn>, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; diff --git a/web/src/components/OrganizationCell/OrganizationCell.mock.ts b/web/src/components/OrganizationCell/OrganizationCell.mock.ts new file mode 100644 index 00000000..9f8df3a3 --- /dev/null +++ b/web/src/components/OrganizationCell/OrganizationCell.mock.ts @@ -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' }], + }, +}) diff --git a/web/src/components/OrganizationCell/OrganizationCell.stories.tsx b/web/src/components/OrganizationCell/OrganizationCell.stories.tsx new file mode 100644 index 00000000..6d825281 --- /dev/null +++ b/web/src/components/OrganizationCell/OrganizationCell.stories.tsx @@ -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 = { + render: () => { + return Loading ? : <> + }, +} + +export const empty: StoryObj = { + render: () => { + return Empty ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/web/src/components/OrganizationCell/OrganizationCell.test.tsx b/web/src/components/OrganizationCell/OrganizationCell.test.tsx new file mode 100644 index 00000000..bf8b2733 --- /dev/null +++ b/web/src/components/OrganizationCell/OrganizationCell.test.tsx @@ -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() + }).not.toThrow() + }) + + it('renders Empty successfully', async () => { + expect(() => { + render() + }).not.toThrow() + }) + + it('renders Failure successfully', async () => { + expect(() => { + render() + }).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() + // }).not.toThrow() + // }) +}) diff --git a/web/src/components/OrganizationCell/OrganizationCell.tsx b/web/src/components/OrganizationCell/OrganizationCell.tsx new file mode 100644 index 00000000..9a7bfcd8 --- /dev/null +++ b/web/src/components/OrganizationCell/OrganizationCell.tsx @@ -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 = () =>
Loading...
+ +export const Empty = () =>
Empty
+ +export const Failure = ({ + error, +}: CellFailureProps) => ( +
Error: {error?.message}
+) + +export const Success = ({ + organization, +}: CellSuccessProps) => { + return ( +
+ + + {organization.reportingPeriods.map((reportingPeriod) => ( + + ))} + + + + {organization.agencies.map((agency) => ( + + ))} + +
+ ) +} diff --git a/web/src/components/Upload/NewUpload/NewUpload.tsx b/web/src/components/Upload/NewUpload/NewUpload.tsx index f3085db3..12b1c98e 100644 --- a/web/src/components/Upload/NewUpload/NewUpload.tsx +++ b/web/src/components/Upload/NewUpload/NewUpload.tsx @@ -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` @@ -26,6 +27,7 @@ const NewUpload = () => { toast.error(error.message) }, }) + const { currentUser } = useAuth() return (
@@ -33,7 +35,11 @@ const NewUpload = () => {

Submit Workbook

- +
) diff --git a/web/src/components/Upload/UploadForm/UploadForm.tsx b/web/src/components/Upload/UploadForm/UploadForm.tsx index 25843459..06b8a13a 100644 --- a/web/src/components/Upload/UploadForm/UploadForm.tsx +++ b/web/src/components/Upload/UploadForm/UploadForm.tsx @@ -5,7 +5,6 @@ import type { EditUploadById } from 'types/graphql' import { Form, FileField, - SelectField, // HiddenField, FormError, FieldError, @@ -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) { @@ -29,6 +30,7 @@ const CREATE_UPLOAD = gql` // type FormUpload = NonNullable interface UploadFormProps { + organizationId: number upload?: EditUploadById['upload'] error: RWGqlError loading: boolean @@ -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 = () => { @@ -101,30 +104,7 @@ const UploadForm = (props: UploadFormProps) => { listClassName="rw-form-error-list" /> {/* 1 */} - - - - - - - - - - - - +