Skip to content

Commit

Permalink
Create new project form skeleton
Browse files Browse the repository at this point in the history
Initialize the parts required for a new project form

closes #1245

Co-authored-by: tangoyankee <[email protected]>
  • Loading branch information
horatiorosa and TangoYankee committed Oct 2, 2024
1 parent 225b9e7 commit 6371b25
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 33 deletions.
45 changes: 45 additions & 0 deletions client/app/components/packages/projects/new.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<SaveableForm
@model={{@package}}
@validators={{array (hash) this.validations.SubmittableProjectsNewForm }}
as |saveableProjectsNewForm|
>
<div class="grid-x grid-margin-x">
<div class="cell large-8">
<section class="form-section">
<h1 class="header-large">
Project Initiation Form
</h1>
<p>
The <b>Project Initiation Form</b> begins the project tracking process and gives NYC Planning the necessary
details before the Informational Interest meeting. By submitting this form, you confirm your intent to file a
Land Use Application with NYC Planning.
</p>
<p>
While some projects might still be in the early stages, all required fields (*) on this form must be completed.
Once submitted, your project will be available to view in this portal. After reviewing your submission, NYC
Planning will contact you with the next steps.
</p>
</section>
<Packages::Projects::ProjectsNewInformation @form={{saveableProjectsNewForm}} />
</div>

<div class="cell large-4 sticky-sidebar">
<saveableProjectsNewForm.PageNav>
<saveableProjectsNewForm.SubmitButton @isEnabled={{saveableProjectsNewForm.isSubmittable}} data-test-save-button />
</saveableProjectsNewForm.PageNav>
<saveableProjectsNewForm.ConfirmationModal @action={{component saveableProjectsNewForm.SubmitButton
isEnabled=saveableProjectsNewForm.isSubmittable onClick=this.submitPackage class="no-margin" }}
@continueButtonTitle="Continue Editing" data-test-confirm-submit-button={{true}}>
<h6>Confirm New Project Submission</h6>
<p class="header-large medium-margin-top small-margin-bottom">
Are you sure?
</p>
<p>
Before submitting, ensure that your answers are accurate and complete, and that necessary attachments (including
the
signature form) have been uploaded.
</p>
</saveableProjectsNewForm.ConfirmationModal>
</div>
</div>
</SaveableForm>
26 changes: 26 additions & 0 deletions client/app/components/packages/projects/new.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import SubmittableProjectsNewForm from '../../../validations/submittable-projects-new-form';


export default class ProjectsNewFormComponent extends Component {
validations = {
SubmittableProjectsNewForm,
};

@service
router;

@service
store;

@action
async submitPackage() {
try {
await this.args.package.submit();
} catch (error) {
console.log('Save new project package error:', error);

Check warning on line 23 in client/app/components/packages/projects/new.js

View workflow job for this annotation

GitHub Actions / 🧪 Test client code

Unexpected console statement

Check warning on line 23 in client/app/components/packages/projects/new.js

View workflow job for this annotation

GitHub Actions / 🧪 Test client code

Unexpected console statement
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{#let @form as |form|}}
<form.Section @title="Project Information">

<Ui::Question @required={{true}} as |Q|>
<Q.Label>
Project Name
</Q.Label>

<form.Field
@attribute="dcpProjectname"
@type="text-input"
id={{Q.questionId}}
@showCounter={{true}}
@maxlength="50"
/>
</Ui::Question>
</form.Section>
{{/let}}
75 changes: 43 additions & 32 deletions client/app/models/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ export default class PackageModel extends Model {
dcpVisibility;

@attr('number')
dcpPackageversion
dcpPackageversion;

@attr('string')
dcpPackagenotes
dcpPackagenotes;

@attr({ defaultValue: () => [] })
documents;
Expand All @@ -101,9 +101,11 @@ export default class PackageModel extends Model {
}

get isLUPackage() {
return this.dcpPackagetype === DCPPACKAGETYPE.DRAFT_LU_PACKAGE.code
|| this.dcpPackagetype === DCPPACKAGETYPE.FILED_LU_PACKAGE.code
|| this.dcpPackagetype === DCPPACKAGETYPE.POST_CERT_LU.code;
return (
this.dcpPackagetype === DCPPACKAGETYPE.DRAFT_LU_PACKAGE.code
|| this.dcpPackagetype === DCPPACKAGETYPE.FILED_LU_PACKAGE.code
|| this.dcpPackagetype === DCPPACKAGETYPE.POST_CERT_LU.code
);
}

setAttrsForSubmission() {
Expand Down Expand Up @@ -192,15 +194,18 @@ export default class PackageModel extends Model {
try {
await this.fileManager.save();
} catch (e) {
console.log('Error saving files: ', e);// eslint-disable-line no-console
console.log('Error saving files: ', e); // eslint-disable-line no-console

// See comment on the tracked fileUploadError property
// definition above.
this.fileUploadErrors = [{
code: 'UPLOAD_DOC_FAILED',
title: 'Failed to upload documents',
detail: 'An error occured while uploading your documents. Please refresh and retry.',
}];
this.fileUploadErrors = [
{
code: 'UPLOAD_DOC_FAILED',
title: 'Failed to upload documents',
detail:
'An error occured while uploading your documents. Please refresh and retry.',
},
];
}

if (this.isLUPackage && this.project.artifact) {
Expand All @@ -211,11 +216,14 @@ export default class PackageModel extends Model {

// See comment on the tracked fileUploadError property
// definition above.
this.fileUploadErrors = [{
code: 'UPLOAD_DOC_FAILED',
title: 'Failed to upload artifact documents',
detail: 'An error occured while uploading your documents. Please refresh and retry.',
}];
this.fileUploadErrors = [
{
code: 'UPLOAD_DOC_FAILED',
title: 'Failed to upload artifact documents',
detail:
'An error occured while uploading your documents. Please refresh and retry.',
},
];
}
}

Expand All @@ -233,7 +241,8 @@ export default class PackageModel extends Model {
get isSingleCeqrInvoiceQuestionnaireDirty() {
if (this.singleCeqrInvoiceQuestionnaire) {
return this.singleCeqrInvoiceQuestionnaire.hasDirtyAttributes;
} return false;
}
return false;
}

async saveDirtySingleCeqrInvoiceQuestionnaire() {
Expand All @@ -250,10 +259,7 @@ export default class PackageModel extends Model {

async saveDeletedRecords(recordsToDelete) {
if (recordsToDelete) {
return Promise.all(
recordsToDelete
.map((record) => record.save()),
);
return Promise.all(recordsToDelete.map((record) => record.save()));
}
}

Expand All @@ -267,22 +273,28 @@ export default class PackageModel extends Model {

get isDirty() {
const isPackageDirty = this.hasDirtyAttributes
|| this.fileManager.isDirty || (this.isLUPackage && this.project.isDirty);
|| this.fileManager.isDirty
|| (this.isLUPackage && this.project.isDirty);

if (this.dcpPackagetype === DCPPACKAGETYPE.PAS_PACKAGE.code) {
return isPackageDirty
return (
isPackageDirty
|| this.pasForm.hasDirtyAttributes
|| this.pasForm.isBblsDirty
|| this.pasForm.isApplicantsDirty
|| this.pasForm.isProjectDirty;
|| this.pasForm.isProjectDirty
);
}
if (this.dcpPackagetype === DCPPACKAGETYPE.RWCDS.code) {
return isPackageDirty
return (
isPackageDirty
|| this.rwcdsForm.hasDirtyAttributes
|| this.rwcdsForm.isAffectedZoningResolutionsDirty;
|| this.rwcdsForm.isAffectedZoningResolutionsDirty
);
}
if (this.isLUPackage) {
return isPackageDirty
return (
isPackageDirty
|| this.landuseForm.hasDirtyAttributes
|| this.landuseForm.isBblsDirty
|| this.landuseForm.isApplicantsDirty
Expand All @@ -291,15 +303,14 @@ export default class PackageModel extends Model {
|| this.landuseForm.isLanduseGeographiesDirty
|| this.landuseForm.isRelatedActionsDirty
|| this.landuseForm.isAffectedZoningResolutionsDirty
|| this.landuseForm.isZoningMapChangesDirty;
|| this.landuseForm.isZoningMapChangesDirty
);
}
if (this.dcpPackagetype === DCPPACKAGETYPE.FILED_EAS.code) {
return isPackageDirty
|| this.isSingleCeqrInvoiceQuestionnaireDirty;
return isPackageDirty || this.isSingleCeqrInvoiceQuestionnaireDirty;
}
if (this.dcpPackagetype === DCPPACKAGETYPE.DRAFT_SCOPE_OF_WORK.code) {
return isPackageDirty
|| this.isSingleCeqrInvoiceQuestionnaireDirty;
return isPackageDirty || this.isSingleCeqrInvoiceQuestionnaireDirty;
}

return isPackageDirty;
Expand Down
4 changes: 4 additions & 0 deletions client/app/models/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,8 @@ export default class ProjectModel extends Model {
.sortBy('dcpPackageversion')
.reverse();
}

async submit() {
await super.save();
}
}
3 changes: 3 additions & 0 deletions client/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export default class Router extends EmberRouterScroll {
Router.map(function() {
// eslint-disable-line
this.route('projects');

this.route(config.featureFlagSelfService ? 'projects/new' : 'not-found', { path: 'projects/new' });

this.route('login');
this.route('logout');

Expand Down
11 changes: 11 additions & 0 deletions client/app/routes/projects/new.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default class ProjectsNewRoute extends Route.extend(AuthenticatedRouteMixin) {
@service store;

async model() {
return await this.store.createRecord('project');
}
}
10 changes: 10 additions & 0 deletions client/app/templates/projects/new.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Ui::Breadcrumbs as | Crumb |>
<Crumb @text="My Projects" @route="projects" />
<Crumb @text="New" @current={{true}} />
</Ui::Breadcrumbs>

<Packages::Projects::New
@package={{@model}}
/>

{{outlet}}
18 changes: 18 additions & 0 deletions client/app/validations/submittable-projects-new-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
validateLength,
validatePresence,
} from 'ember-changeset-validations/validators';

export default {
dcpProjectname: [
validateLength({
min: 0,
max: 50,
message: 'Text is too long (max {max} characters)',
}),
validatePresence({
presence: true,
message: 'This field is required',
}),
],
};
11 changes: 11 additions & 0 deletions client/tests/unit/routes/projects/new-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

module('Unit | Route | projects/new', function(hooks) {
setupTest(hooks);

test('it exists', function(assert) {
const route = this.owner.lookup('route:projects/new');
assert.ok(route);
});
});
17 changes: 16 additions & 1 deletion server/src/projects/projects.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import {
Get,
Patch,
Body,
Query,
HttpException,
HttpStatus,
Session,
UseInterceptors,
UseGuards,
UsePipes,
Param,
Post,
} from '@nestjs/common';
import { ProjectsService } from './projects.service';
import { ConfigService } from '../config/config.service';
Expand Down Expand Up @@ -129,6 +129,21 @@ export class ProjectsController {
}
}

@Post('/')
async createProject(@Body() body) {
if (!this.config.featureFlag.selfService) {
throw new HttpException({
code: "NOT_FOUND",
title: "Not found",
},
HttpStatus.NOT_FOUND)
}

return {
...body
}
}

@Get('/:id')
async projectById(@Param('id') id) {
try {
Expand Down

0 comments on commit 6371b25

Please sign in to comment.