diff --git a/client/app/components/packages/projects/new.hbs b/client/app/components/packages/projects/new.hbs
new file mode 100644
index 00000000..589721b5
--- /dev/null
+++ b/client/app/components/packages/projects/new.hbs
@@ -0,0 +1,45 @@
+
+
+
\ No newline at end of file
diff --git a/client/app/components/packages/projects/new.js b/client/app/components/packages/projects/new.js
new file mode 100644
index 00000000..0c688125
--- /dev/null
+++ b/client/app/components/packages/projects/new.js
@@ -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);
+ }
+ }
+}
diff --git a/client/app/components/packages/projects/projects-new-information.hbs b/client/app/components/packages/projects/projects-new-information.hbs
new file mode 100644
index 00000000..7cd975ef
--- /dev/null
+++ b/client/app/components/packages/projects/projects-new-information.hbs
@@ -0,0 +1,18 @@
+{{#let @form as |form|}}
+
+
+
+
+ Project Name
+
+
+
+
+
+{{/let}}
\ No newline at end of file
diff --git a/client/app/models/package.js b/client/app/models/package.js
index 0493d765..729341a9 100644
--- a/client/app/models/package.js
+++ b/client/app/models/package.js
@@ -85,10 +85,10 @@ export default class PackageModel extends Model {
dcpVisibility;
@attr('number')
- dcpPackageversion
+ dcpPackageversion;
@attr('string')
- dcpPackagenotes
+ dcpPackagenotes;
@attr({ defaultValue: () => [] })
documents;
@@ -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() {
@@ -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) {
@@ -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.',
+ },
+ ];
}
}
@@ -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() {
@@ -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()));
}
}
@@ -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
@@ -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;
diff --git a/client/app/models/project.js b/client/app/models/project.js
index dcf7ae07..d3302998 100644
--- a/client/app/models/project.js
+++ b/client/app/models/project.js
@@ -233,4 +233,8 @@ export default class ProjectModel extends Model {
.sortBy('dcpPackageversion')
.reverse();
}
+
+ async submit() {
+ await super.save();
+ }
}
diff --git a/client/app/router.js b/client/app/router.js
index 9d563e78..18bad84f 100644
--- a/client/app/router.js
+++ b/client/app/router.js
@@ -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');
diff --git a/client/app/routes/projects/new.js b/client/app/routes/projects/new.js
new file mode 100644
index 00000000..4483eec6
--- /dev/null
+++ b/client/app/routes/projects/new.js
@@ -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');
+ }
+}
diff --git a/client/app/templates/projects/new.hbs b/client/app/templates/projects/new.hbs
new file mode 100644
index 00000000..36675f77
--- /dev/null
+++ b/client/app/templates/projects/new.hbs
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+{{outlet}}
\ No newline at end of file
diff --git a/client/app/validations/submittable-projects-new-form.js b/client/app/validations/submittable-projects-new-form.js
new file mode 100644
index 00000000..2c00a391
--- /dev/null
+++ b/client/app/validations/submittable-projects-new-form.js
@@ -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',
+ }),
+ ],
+};
diff --git a/client/tests/unit/routes/projects/new-test.js b/client/tests/unit/routes/projects/new-test.js
new file mode 100644
index 00000000..c6c8f1e0
--- /dev/null
+++ b/client/tests/unit/routes/projects/new-test.js
@@ -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);
+ });
+});
diff --git a/server/src/projects/projects.controller.ts b/server/src/projects/projects.controller.ts
index bf12a75b..c5f7dc83 100644
--- a/server/src/projects/projects.controller.ts
+++ b/server/src/projects/projects.controller.ts
@@ -3,7 +3,6 @@ import {
Get,
Patch,
Body,
- Query,
HttpException,
HttpStatus,
Session,
@@ -11,6 +10,7 @@ import {
UseGuards,
UsePipes,
Param,
+ Post,
} from '@nestjs/common';
import { ProjectsService } from './projects.service';
import { ConfigService } from '../config/config.service';
@@ -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 {