From 88d490959a3a3d408aa66524f6a4c45c214fb7ad Mon Sep 17 00:00:00 2001 From: dinesh Date: Mon, 2 Feb 2026 16:05:43 -0800 Subject: [PATCH 1/4] demo env setup related changes --- .../submit-api/templates/demo-db-secret.yaml | 14 ++++++++ .../submit-api/templates/deployment.yaml | 36 +++++++++++++++++++ .../charts/submit-api/templates/secret.yaml | 2 +- deployment/charts/submit-api/values.yaml | 6 ++++ .../versions/fb95dbfcb9d9_add_new_status.py | 17 +++++++-- 5 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 deployment/charts/submit-api/templates/demo-db-secret.yaml diff --git a/deployment/charts/submit-api/templates/demo-db-secret.yaml b/deployment/charts/submit-api/templates/demo-db-secret.yaml new file mode 100644 index 000000000..5d4992a60 --- /dev/null +++ b/deployment/charts/submit-api/templates/demo-db-secret.yaml @@ -0,0 +1,14 @@ +{{- if .Values.database.demo.enabled }} +apiVersion: v1 +kind: Secret +metadata: + labels: + app: {{ .Release.Name }} + name: {{ .Release.Name }}-{{ .Values.database.demo.suffix }} + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} +type: Opaque +stringData: + app-db-username: {{ .Values.database.demo.username | quote }} + app-db-password: {{ .Values.database.demo.password | quote }} + app-db-name: {{ .Values.database.demo.name | quote }} +{{- end }} diff --git a/deployment/charts/submit-api/templates/deployment.yaml b/deployment/charts/submit-api/templates/deployment.yaml index d7a11d8ac..60f6ed92d 100644 --- a/deployment/charts/submit-api/templates/deployment.yaml +++ b/deployment/charts/submit-api/templates/deployment.yaml @@ -25,6 +25,23 @@ spec: command: - /opt/app-root/pre-hook-update-db.sh env: + {{- if .Values.database.demo.enabled }} + - name: DATABASE_USERNAME + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-username + - name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-password + - name: DATABASE_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-name + {{- else }} - name: DATABASE_USERNAME valueFrom: secretKeyRef: @@ -40,6 +57,7 @@ spec: secretKeyRef: name: {{ .Values.database.secret }} key: app-db-name + {{- end }} - name: DATABASE_HOST value: {{ .Values.database.service.name }} - name: DATABASE_PORT @@ -52,6 +70,23 @@ spec: - containerPort: 8080 protocol: TCP env: + {{- if .Values.database.demo.enabled }} + - name: DATABASE_USERNAME + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-username + - name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-password + - name: DATABASE_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.database.secret }}-{{ .Values.database.demo.suffix }} + key: app-db-name + {{- else }} - name: DATABASE_USERNAME valueFrom: secretKeyRef: @@ -67,6 +102,7 @@ spec: secretKeyRef: name: {{ .Values.database.secret }} key: app-db-name + {{- end }} - name: DATABASE_HOST value: {{ .Values.database.service.name }} - name: DATABASE_PORT diff --git a/deployment/charts/submit-api/templates/secret.yaml b/deployment/charts/submit-api/templates/secret.yaml index cef14ea84..ca3737c9b 100644 --- a/deployment/charts/submit-api/templates/secret.yaml +++ b/deployment/charts/submit-api/templates/secret.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: labels: - app: {{ .Values.app_group }} + app: {{ .Release.Name }} name: {{ .Release.Name }} name: {{ .Release.Name }} stringData: diff --git a/deployment/charts/submit-api/values.yaml b/deployment/charts/submit-api/values.yaml index 13df662af..f2df987f1 100644 --- a/deployment/charts/submit-api/values.yaml +++ b/deployment/charts/submit-api/values.yaml @@ -19,6 +19,12 @@ database: service: name: submit-patroni port: 5432 + demo: + enabled: false + suffix: demo + username: "" + password: "" + name: "" service: type: ClusterIP diff --git a/submit-api/migrations/versions/fb95dbfcb9d9_add_new_status.py b/submit-api/migrations/versions/fb95dbfcb9d9_add_new_status.py index 169733936..a78db92cc 100644 --- a/submit-api/migrations/versions/fb95dbfcb9d9_add_new_status.py +++ b/submit-api/migrations/versions/fb95dbfcb9d9_add_new_status.py @@ -22,7 +22,13 @@ def upgrade(): DECLARE itemstatus_values text[]; packagestatus_values text[]; + items_count integer; + packages_count integer; BEGIN + -- Check if tables have data + SELECT COUNT(*) INTO items_count FROM items; + SELECT COUNT(*) INTO packages_count FROM packages; + -- Get existing values SELECT array_agg(quote_literal(enumlabel)) INTO itemstatus_values FROM pg_enum WHERE enumtypid = 'itemstatus'::regtype; SELECT array_agg(quote_literal(enumlabel)) INTO packagestatus_values FROM pg_enum WHERE enumtypid = 'packagestatus'::regtype; @@ -35,9 +41,14 @@ def upgrade(): ALTER TABLE items ALTER COLUMN status TYPE itemstatus_new USING status::text::itemstatus_new; ALTER TABLE packages ALTER COLUMN status TYPE packagestatus_new[] USING status::text[]::packagestatus_new[]; - -- Update data - UPDATE items SET status = 'NEW' WHERE status = 'NEW_SUBMISSION'; - UPDATE packages SET status = array_replace(status, 'NEW_SUBMISSION', 'NEW'); + -- Update data only if tables have rows + IF items_count > 0 THEN + UPDATE items SET status = 'NEW' WHERE status = 'NEW_SUBMISSION'; + END IF; + + IF packages_count > 0 THEN + UPDATE packages SET status = array_replace(status, 'NEW_SUBMISSION', 'NEW'); + END IF; -- Drop old types and rename new ones DROP TYPE itemstatus; From 0cf47cfb170592a5788fa2cbe7d2acbdfe00aad9 Mon Sep 17 00:00:00 2001 From: dinesh Date: Wed, 8 Apr 2026 10:11:50 -0700 Subject: [PATCH 2/4] Additional information submission --- submit-api/requirements.txt | Bin 1047 -> 2930 bytes submit-api/requirements/prod.txt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/submit-api/requirements.txt b/submit-api/requirements.txt index 8129d9dcb251d35b474b29ebf61b3be2285500e5..5019313dbd6361790c58384dc0d48dc8f7b8f86b 100644 GIT binary patch literal 2930 zcmZ{mTWcdn5QXbGkpB<}EbIYS7LLUjAqFRZzuqhi-!L(?&YTzY9;0~eP8Ph z$VsXI-dGgai^(ik&7|b&TApT^i)ma5xs@ffsP&8gi%tvgAy1Cr*W7t()UXmLLXOMY zAbys8@`)O&?vqMR9EXCNFtT{q+spZ3;A-NdKN+Fmvn+SBS&YN+r35BcASYl|AC zRo6k^D%r>Px~T&)@Tt?R)bC^4n@0ayI$3>Z+4dh}_p-c{3Uz0-pC$5O6^=rkg!z1uv~a8&F*zk?Du<2--%b@!t>-sc zT{ntuoXqUK?SLEYp#x5xPVNPA>X~8w&*28zb&&5$9_S>d6LZJ*P;#v3tpxSwh^e^` z!n8`8kG-&V)asq=zSH+>SqEnw+YWlU8o`Zw{qsC>Ageq1*mfMy)$Cr{af*-G(@*P( zTA@zURrvRzZ9e18ZM8^SoD|M=@E53Fo47 zXe*_nIE5=&!5XTx_2z2z8BMov+Ho@4&otF5GoQ)LImo@C)QTe`s*~a<6V z%r-i0u6&M#xz_K6P~810J!5ek>CHswSGj(vwXgMdrO)d}{;o1RoA{=A3s*8;i6f^z zIqUO-|3Mh^1F=$S6hdYdNa2l+3zsgmPj^mlYE!h1hj4Q?um&ljjKYthu zZGtm+y>hNW&4$@(NVYJ6ae`d;R^-Qut=2K^J$T(5q{_}(aO)I%VFwl5OuK?s&YrYA zi+UyAvU7AcQeRO-uOxOPMbgOSRkhe=b%P;m*m%XB#pqT86-N-p*}sS*tdqKi-HfPE zcAf}IWw-hGX2jJo4Ts;p5)qtM%nLb+VO?JfjE{?SeyEFswjy9yHAw^x=^kTU3`Afh zbd<<>IxHLntT%|Uz>%gy$3^d_dGa}=h5uTfUjO7`x^KUvle0zdlCu9uKkYfFqYBE( ztOrK#P!`nNjK+DsO=1.2.2 flask-jwt-oidc python-dotenv psycopg2-binary From c894158b10ecbb871eb25fc81906858e0c6b3557 Mon Sep 17 00:00:00 2001 From: dinesh Date: Thu, 9 Apr 2026 16:32:02 -0700 Subject: [PATCH 3/4] Additional information submission --- .gitignore | 1 + ..._add_description_and_unique_constraint_.py | 40 +++++ submit-api/requirements.txt | Bin 2930 -> 1262 bytes submit-api/requirements/prod.txt | 2 +- .../src/submit_api/enums/package_type.py | 1 + .../src/submit_api/models/account_project.py | 9 +- submit-api/src/submit_api/models/package.py | 1 + .../src/submit_api/models/package_type.py | 16 +- .../src/submit_api/resources/package_type.py | 29 ++- .../schemas/account_project_work.py | 20 +++ submit-api/src/submit_api/schemas/package.py | 6 + .../src/submit_api/schemas/package_type.py | 1 + .../submit_api/schemas/package_type_create.py | 10 ++ .../schemas/package_type_response.py | 4 + submit-api/src/submit_api/schemas/project.py | 15 +- .../submit_api/services/package_service.py | 35 +++- .../services/package_type_service.py | 38 ++-- .../AdditionalInformationForm.tsx | 44 +++++ .../NewAssessmentSubmissionForm.tsx | 167 ++++++++++++++---- .../NewAssessmentSubmission/index.tsx | 8 +- .../App/Projects/ProjectSubmissionsCard.tsx | 4 +- .../App/Submission/InfoBox/index.tsx | 62 +++---- .../App/Submission/SubmissionTitle.tsx | 47 +++-- .../ProponentView/constants.ts | 11 ++ .../ProponentView/index.tsx | 160 +++++++++++++++++ .../ItemForm/ProponentItemForm.tsx | 5 +- .../addProjects/ProjectStatus.tsx | 15 +- submit-web/src/hooks/api/constants.ts | 1 + submit-web/src/hooks/api/useObjectStorage.ts | 4 + submit-web/src/hooks/api/usePackageTypes.ts | 39 ++++ submit-web/src/models/AccountProjectWork.ts | 7 + submit-web/src/models/Package.ts | 4 + submit-web/src/models/SubmissionItem.ts | 4 +- .../_projectLayout/new-submission.tsx | 2 +- .../submissions/$submissionId.tsx | 1 - 35 files changed, 681 insertions(+), 132 deletions(-) create mode 100644 submit-api/migrations/versions/d4ea378228e4_add_description_and_unique_constraint_.py create mode 100644 submit-api/src/submit_api/schemas/account_project_work.py create mode 100644 submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/AdditionalInformationForm.tsx create mode 100644 submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/constants.ts create mode 100644 submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/index.tsx create mode 100644 submit-web/src/hooks/api/usePackageTypes.ts create mode 100644 submit-web/src/models/AccountProjectWork.ts diff --git a/.gitignore b/.gitignore index d1fae41d7..816147f66 100644 --- a/.gitignore +++ b/.gitignore @@ -168,3 +168,4 @@ deployment/charts/submit-web/values.prod.yaml deployment/charts/submit-api/values.prod.yaml deployment/charts/submit-api/values.dev.yaml deployment/charts/submit-web/values.dev.yaml +.windsurf/ \ No newline at end of file diff --git a/submit-api/migrations/versions/d4ea378228e4_add_description_and_unique_constraint_.py b/submit-api/migrations/versions/d4ea378228e4_add_description_and_unique_constraint_.py new file mode 100644 index 000000000..01109d41a --- /dev/null +++ b/submit-api/migrations/versions/d4ea378228e4_add_description_and_unique_constraint_.py @@ -0,0 +1,40 @@ +"""add_title_and_unique_constraint_to_package_types + +Revision ID: d4ea378228e4 +Revises: db8937ea18af +Create Date: 2026-04-08 22:21:47.688586 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd4ea378228e4' +down_revision = 'db8937ea18af' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('package_types', schema=None) as batch_op: + batch_op.add_column(sa.Column('title', sa.String(length=255), nullable=True, comment='Display title for the package type')) + batch_op.create_unique_constraint('uq_package_type_name_phase', ['name', 'phase_id']) + + with op.batch_alter_table('packages', schema=None) as batch_op: + batch_op.add_column(sa.Column('description', sa.String(length=500), nullable=True, comment='Description of the package')) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('packages', schema=None) as batch_op: + batch_op.drop_column('description') + + with op.batch_alter_table('package_types', schema=None) as batch_op: + batch_op.drop_constraint('uq_package_type_name_phase', type_='unique') + batch_op.drop_column('title') + + # ### end Alembic commands ### diff --git a/submit-api/requirements.txt b/submit-api/requirements.txt index 5019313dbd6361790c58384dc0d48dc8f7b8f86b..f6de89d7c26766f1a4510fb590528602a1adc685 100644 GIT binary patch literal 1262 zcmZ8h%Wm5+5WMqWMCf5V_CbdtKo3C!v`C8_4Vt1QS`^8UR1^8@J4+?4Q~0#Y-JPA; zk%dvyNz1macy-5XCajKbzbh+bN?!7ciIhTY+j`44yksY%?Wh9P9}r3*2W9lBZBg1# zLWQKy8uewp;}zd9dCnnb;dKxps#I7PCSmlI1~r(ADx>AtwtLbFVF+u^N6g zrTYsZ(W25B7sMne-tZlhVe!fJLHJ>5+szJmJ9gI2q5|#23|}i@^;hkf!A;)+^_Q z?Zmrq4eNta)+o$sa$`SR4H`Dzly0Uw5((WETeZPKkHB(skSep?0#B#d3EQjSX5?yK zqw_)Ai>O!R9lJzlBkh7|8;o0eCE*My5{^O>N?7WEg&)P}R#H`oAdItr5@*PP z-EfRgvVk}mx#9yO?P1`sk9fzexe0v!Ko@C@V8D$ae?C zpk8L|oUhi9e8G3IASqBl!bBzK074{Fg(%JVl$=4se)V)5gjXiZKp$e%*@gJSDA}z6 zVF|uD+@y+oXOp(`dLc5zzw+W27y$w;L_E34(BB3uTC%iw5ICwgP>ZWw@NLkU(iLLB iU+dosn}dN_8|vG^E6*y7S2g3N^eyb!b@g*bq4z&k)_=YL literal 2930 zcmZ{mTWcdn5QXbGkpB<}EbIYS7LLUjAqFRZzuqhi-!L(?&YTzY9;0~eP8Ph z$VsXI-dGgai^(ik&7|b&TApT^i)ma5xs@ffsP&8gi%tvgAy1Cr*W7t()UXmLLXOMY zAbys8@`)O&?vqMR9EXCNFtT{q+spZ3;A-NdKN+Fmvn+SBS&YN+r35BcASYl|AC zRo6k^D%r>Px~T&)@Tt?R)bC^4n@0ayI$3>Z+4dh}_p-c{3Uz0-pC$5O6^=rkg!z1uv~a8&F*zk?Du<2--%b@!t>-sc zT{ntuoXqUK?SLEYp#x5xPVNPA>X~8w&*28zb&&5$9_S>d6LZJ*P;#v3tpxSwh^e^` z!n8`8kG-&V)asq=zSH+>SqEnw+YWlU8o`Zw{qsC>Ageq1*mfMy)$Cr{af*-G(@*P( zTA@zURrvRzZ9e18ZM8^SoD|M=@E53Fo47 zXe*_nIE5=&!5XTx_2z2z8BMov+Ho@4&otF5GoQ)LImo@C)QTe`s*~a<6V z%r-i0u6&M#xz_K6P~810J!5ek>CHswSGj(vwXgMdrO)d}{;o1RoA{=A3s*8;i6f^z zIqUO-|3Mh^1F=$S6hdYdNa2l+3zsgmPj=1.2.2 +flask-marshmallow==1.4.0 flask-jwt-oidc python-dotenv psycopg2-binary diff --git a/submit-api/src/submit_api/enums/package_type.py b/submit-api/src/submit_api/enums/package_type.py index a32abe0da..0656f5a6d 100644 --- a/submit-api/src/submit_api/enums/package_type.py +++ b/submit-api/src/submit_api/enums/package_type.py @@ -12,6 +12,7 @@ class PackageTypeEnum(enum.Enum): MANAGEMENT_PLAN = 'Management Plan' IEM = 'IEM' + ADDITIONAL_INFORMATION = 'Additional Information' class PackageTypeId(enum.Enum): diff --git a/submit-api/src/submit_api/models/account_project.py b/submit-api/src/submit_api/models/account_project.py index df6a10909..9fca6a3eb 100644 --- a/submit-api/src/submit_api/models/account_project.py +++ b/submit-api/src/submit_api/models/account_project.py @@ -40,8 +40,14 @@ class AccountProject(BaseModel): def latest_packages(self): """Get the latest packages by versions for the account project.""" version_by_package = {} + packages_without_versions = [] for package in self.packages: + # Handle packages without versions (e.g., Additional Information) + if not package.version: + packages_without_versions.append(package) + continue + original_package_id = package.version.original_package_id if original_package_id not in version_by_package: version_by_package[original_package_id] = package @@ -49,7 +55,8 @@ def latest_packages(self): if package.version.version > version_by_package[original_package_id].version.version: version_by_package[original_package_id] = package - return list(version_by_package.values()) + # Return both versioned packages (latest only) and packages without versions (all) + return list(version_by_package.values()) + packages_without_versions @classmethod def add_projects_bulk(cls, projects): diff --git a/submit-api/src/submit_api/models/package.py b/submit-api/src/submit_api/models/package.py index f01fe6a31..5dd062173 100644 --- a/submit-api/src/submit_api/models/package.py +++ b/submit-api/src/submit_api/models/package.py @@ -78,6 +78,7 @@ class Package(BaseModel): account_project_id = Column(db.Integer, ForeignKey( 'account_projects.id', ondelete='CASCADE'), nullable=False) name = Column(db.String(255), nullable=False) + description = Column(db.String(500), nullable=True, comment="Description of the package") type_id = Column(db.Integer, ForeignKey( 'package_types.id'), nullable=False) type = db.relationship('PackageType', foreign_keys=[ diff --git a/submit-api/src/submit_api/models/package_type.py b/submit-api/src/submit_api/models/package_type.py index 07618cf15..1ae6fbb55 100644 --- a/submit-api/src/submit_api/models/package_type.py +++ b/submit-api/src/submit_api/models/package_type.py @@ -4,7 +4,7 @@ """ from __future__ import annotations -from sqlalchemy import Column, ForeignKey +from sqlalchemy import Column, ForeignKey, UniqueConstraint from sqlalchemy.orm import relationship from .base_model import BaseModel @@ -15,9 +15,13 @@ class PackageType(BaseModel): """Definition of the package type entity.""" __tablename__ = 'package_types' + __table_args__ = ( + UniqueConstraint('name', 'phase_id', name='uq_package_type_name_phase'), + ) id = Column(db.Integer, primary_key=True, autoincrement=True) name = Column(db.String(255), nullable=False) + title = Column(db.String(255), nullable=True, comment="Display title for the package type") phase_id = Column(db.Integer, ForeignKey('track_phases.id'), nullable=True) phase = relationship('TrackPhase', foreign_keys=[phase_id], lazy='joined') item_types = relationship('ItemType', secondary='package_item_types', back_populates='package_types') @@ -26,3 +30,13 @@ class PackageType(BaseModel): def find_by_name(cls, name: str): """Return model by name.""" return cls.query.filter_by(name=name).first() + + @classmethod + def find_by_name_and_phase(cls, name: str, phase_id: int): + """Return model by name and phase_id.""" + return cls.query.filter_by(name=name, phase_id=phase_id).first() + + @classmethod + def find_by_phase_id(cls, phase_id: int): + """Return all package types for a given phase_id, ordered by id.""" + return cls.query.filter_by(phase_id=phase_id).order_by(cls.id).all() diff --git a/submit-api/src/submit_api/resources/package_type.py b/submit-api/src/submit_api/resources/package_type.py index 664ba0109..8ce810514 100644 --- a/submit-api/src/submit_api/resources/package_type.py +++ b/submit-api/src/submit_api/resources/package_type.py @@ -5,7 +5,9 @@ from flask_restx import Namespace, Resource from submit_api.auth import auth +from submit_api.models.package_type import PackageType from submit_api.resources.apihelper import Api as ApiHelper +from submit_api.schemas.package_type import PackageTypeSchema from submit_api.schemas.package_type_create import PackageTypeCreateSchema from submit_api.schemas.package_type_response import PackageTypeResponseSchema from submit_api.services.package_type_service import PackageTypeService @@ -27,6 +29,25 @@ ) +@cors_preflight('GET,OPTIONS') +@API.route('/phase/', methods=['GET', 'OPTIONS']) +class PackageTypeByPhaseResource(Resource): + """Resource for fetching package types by phase.""" + + @API.doc('get_package_types_by_phase') + @API.response( + code=HTTPStatus.OK, + model=[package_type_response_model], + description='Package types retrieved successfully' + ) + @auth.require + def get(self, phase_id): + """Get all package types for a given phase.""" + package_types = PackageType.find_by_phase_id(phase_id) + schema = PackageTypeSchema(many=True) + return schema.dump(package_types), HTTPStatus.OK + + @cors_preflight('POST,OPTIONS') @API.route('', methods=['POST', 'OPTIONS']) class PackageTypeResource(Resource): @@ -63,12 +84,6 @@ def post(self): data = schema.load(request.get_json()) # Create or update package type - result = PackageTypeService.create_or_update_package_type( - ea_act_name=data['ea_act_name'], - work_type_name=data['work_type_name'], - phase_name=data['phase_name'], - package_type_name=data['package_type_name'], - item_types=data['item_types'] - ) + result = PackageTypeService.create_or_update_package_type(data) return result, HTTPStatus.OK diff --git a/submit-api/src/submit_api/schemas/account_project_work.py b/submit-api/src/submit_api/schemas/account_project_work.py new file mode 100644 index 000000000..18aa3bd77 --- /dev/null +++ b/submit-api/src/submit_api/schemas/account_project_work.py @@ -0,0 +1,20 @@ +"""AccountProjectWork schema. + +This module defines the schema for the account_project_work entity. +""" +from marshmallow import EXCLUDE, Schema, fields + +from submit_api.schemas.track_work import TrackWorkSchema + + +class AccountProjectWorkSchema(Schema): + """Account project work schema.""" + + class Meta: # pylint: disable=too-few-public-methods + """Exclude unknown fields in the deserialized output.""" + + unknown = EXCLUDE + + id = fields.Int(data_key="id") + work_id = fields.Int(data_key="work_id") + work = fields.Nested(TrackWorkSchema, data_key="work") diff --git a/submit-api/src/submit_api/schemas/package.py b/submit-api/src/submit_api/schemas/package.py index fe059df98..c186786b0 100644 --- a/submit-api/src/submit_api/schemas/package.py +++ b/submit-api/src/submit_api/schemas/package.py @@ -11,6 +11,7 @@ from submit_api.models.user import UserType from submit_api.schemas.item import ItemSchema, StaffItemSchema from submit_api.schemas.package_type import PackageTypeSchema +from submit_api.schemas.account_project_work import AccountProjectWorkSchema from submit_api.services.user_service import UserService from submit_api.utils.token_info import TokenInfo from submit_api.schemas.internal_staff_document import InternalStaffDocumentSchema @@ -59,8 +60,10 @@ class Meta: # pylint: disable=too-few-public-methods unknown = EXCLUDE name = fields.Str(data_key="name") + description = fields.Str(data_key="description", required=False) metadata = fields.Dict(data_key="metadata") type = fields.Str(data_key="type") + account_project_work_id = fields.Int(data_key="account_project_work_id", required=False, allow_none=True) class PostPackageState(Schema): @@ -136,6 +139,7 @@ class Meta: # pylint: disable=too-few-public-methods id = fields.Int(data_key="id") account_project_id = fields.Int(data_key="account_project_id") name = fields.Str(data_key="name") + description = fields.Str(data_key="description") type = fields.Nested(PackageTypeSchema, data_key="type") type_id = fields.Int(data_key="type_id") status = fields.List(fields.Enum(enum=PackageStatus), data_key="status", metadata={"enum": PackageStatus}) @@ -148,6 +152,8 @@ class Meta: # pylint: disable=too-few-public-methods PackageUpdateRequestSchema, data_key="update_requests", many=True) version = fields.Nested(PackageVersionSchema, data_key="version", exclude=["package_id"]) + account_project_work = fields.Nested( + AccountProjectWorkSchema, data_key="account_project_work", allow_none=True) def get_submitted_by(self, obj): """Get submitted by.""" diff --git a/submit-api/src/submit_api/schemas/package_type.py b/submit-api/src/submit_api/schemas/package_type.py index 87facca63..81875ba0a 100644 --- a/submit-api/src/submit_api/schemas/package_type.py +++ b/submit-api/src/submit_api/schemas/package_type.py @@ -16,3 +16,4 @@ class Meta: # pylint: disable=too-few-public-methods id = fields.Int(data_key="id") name = fields.Str(data_key="name") + title = fields.Str(data_key="title", required=False) diff --git a/submit-api/src/submit_api/schemas/package_type_create.py b/submit-api/src/submit_api/schemas/package_type_create.py index 2e815d6d4..cf0822dcb 100644 --- a/submit-api/src/submit_api/schemas/package_type_create.py +++ b/submit-api/src/submit_api/schemas/package_type_create.py @@ -24,6 +24,11 @@ class Meta: # pylint: disable=too-few-public-methods data_key="name", metadata={"description": "Name for new item type"} ) + description = fields.Str( + required=False, + data_key="description", + metadata={"description": "Description for new item type"} + ) submission_method = fields.Str( required=False, data_key="submission_method", @@ -73,6 +78,11 @@ class Meta: # pylint: disable=too-few-public-methods data_key="package_type_name", metadata={"description": "Name of the package type to create"} ) + package_type_title = fields.Str( + required=True, + data_key="package_type_title", + metadata={"description": "Display title for the package type"} + ) item_types = fields.List( fields.Nested(ItemTypeSchema), required=True, diff --git a/submit-api/src/submit_api/schemas/package_type_response.py b/submit-api/src/submit_api/schemas/package_type_response.py index 600cd4cae..6a100aaa3 100644 --- a/submit-api/src/submit_api/schemas/package_type_response.py +++ b/submit-api/src/submit_api/schemas/package_type_response.py @@ -44,6 +44,10 @@ class Meta: # pylint: disable=too-few-public-methods required=True, metadata={"description": "Package type name"} ) + title = fields.Str( + required=False, + metadata={"description": "Display title for the package type"} + ) phase_id = fields.Int( required=True, metadata={"description": "Associated phase ID from track_phases table"} diff --git a/submit-api/src/submit_api/schemas/project.py b/submit-api/src/submit_api/schemas/project.py index 41032287d..3014bd456 100644 --- a/submit-api/src/submit_api/schemas/project.py +++ b/submit-api/src/submit_api/schemas/project.py @@ -8,7 +8,7 @@ from submit_api.schemas.package import PackageSchema, StaffPackageSchema from submit_api.schemas.proponent import ProponentSchema -from submit_api.schemas.track_work import TrackWorkSchema +from submit_api.schemas.account_project_work import AccountProjectWorkSchema class ProjectSchema(Schema): @@ -49,19 +49,6 @@ class Meta: # pylint: disable=too-few-public-methods items = fields.Function(lambda obj: []) -class AccountProjectWorkSchema(Schema): - """Account project work schema.""" - - class Meta: # pylint: disable=too-few-public-methods - """Exclude unknown fields in the deserialized output.""" - - unknown = EXCLUDE - - id = fields.Int(data_key="id") - work_id = fields.Int(data_key="work_id") - work = fields.Nested(TrackWorkSchema, data_key="work") - - class AccountProjectSchema(Schema): """Account project schema.""" diff --git a/submit-api/src/submit_api/services/package_service.py b/submit-api/src/submit_api/services/package_service.py index 045796407..46fb4c231 100644 --- a/submit-api/src/submit_api/services/package_service.py +++ b/submit-api/src/submit_api/services/package_service.py @@ -14,6 +14,7 @@ from submit_api.models import PackageType as PackageTypeModel from submit_api.models import PackageVersion as PackageVersionModel from submit_api.models import UpdateRequest as UpdateRequestModel +from submit_api.models.account_project_work import AccountProjectWork as AccountProjectWorkModel from submit_api.models.db import session_scope from submit_api.models.email_queue import EmailQueue as EmailQueueModel from submit_api.models.email_queue import EntityType @@ -63,10 +64,17 @@ def create_first_package(cls, account_project_id, request_data): package = cls._create_package( session, account_project_id, request_data, package_type) - package_version = cls._create_package_version( - session, original_package_id=package.id, version=1) - package.version_id = package_version.id - session.add(package) + + # Skip package version creation for Additional Information packages + # Additional Information packages are simple document uploads that don't require versioning + # They can be associated with any phase and don't follow the review/approval workflow + # that requires version tracking + if package_type.name != PackageTypeEnum.ADDITIONAL_INFORMATION.value: + package_version = cls._create_package_version( + session, original_package_id=package.id, version=1) + package.version_id = package_version.id + session.add(package) + cls._create_package_metadata( session, package.id, request_data.get("metadata")) cls._create_items(session, package.id, package_type) @@ -80,11 +88,30 @@ def _create_package(session, account_project_id, request_data, package_type): package_data = { "account_project_id": account_project_id, "name": request_data.get("name"), + "description": request_data.get("description"), "type_id": package_type.id, } if status := request_data.get("status"): package_data["status"] = status + # Use account_project_work_id from request if provided + if request_data.get("account_project_work_id"): + package_data["account_project_work_id"] = request_data.get("account_project_work_id") + current_app.logger.info( + f"Using account_project_work_id from request: {request_data.get('account_project_work_id')}" + ) + # Otherwise, try to find it automatically if package type has a phase + elif package_type.phase_id: + # Find the account_project_work that matches this phase + account_project_works = AccountProjectWorkModel.find_by_account_project_id(account_project_id) + for apw in account_project_works: + if apw.work and apw.work.current_phase_id == package_type.phase_id: + package_data["account_project_work_id"] = apw.id + current_app.logger.info( + f"Auto-associating package with work {apw.work_id} (phase: {package_type.phase_id})" + ) + break + package = PackageModel(**package_data) session.add(package) session.flush() diff --git a/submit-api/src/submit_api/services/package_type_service.py b/submit-api/src/submit_api/services/package_type_service.py index 13d0ee57a..379df24dc 100644 --- a/submit-api/src/submit_api/services/package_type_service.py +++ b/submit-api/src/submit_api/services/package_type_service.py @@ -108,25 +108,21 @@ def _create_item_type_associations( db.session.add(package_item_type) @staticmethod - def create_or_update_package_type( - ea_act_name: str, - work_type_name: str, - phase_name: str, - package_type_name: str, - item_types: List[Dict[str, Any]] - ) -> Dict[str, Any]: + def create_or_update_package_type(data: Dict[str, Any]) -> Dict[str, Any]: """Create or update a package type with phase association. This method is idempotent - it will create a new package type if it doesn't exist, or update the existing one if it does. It also creates new item types if they don't exist. Args: - ea_act_name: Environmental Assessment Act name - work_type_name: Work type name - phase_name: Phase name (can be display_name or name) - package_type_name: Name of the package type to create/update - item_types: List of item type definitions (either {'id': int} or - {'name': str, 'submission_method': str}) + data: Dictionary containing: + - ea_act_name: Environmental Assessment Act name + - work_type_name: Work type name + - phase_name: Phase name (can be display_name or name) + - package_type_name: Name of the package type to create/update + - package_type_title: Display title for the package type + - item_types: List of item type definitions (either {'id': int} or + {'name': str, 'submission_method': str}) Returns: Dict containing the created/updated package type information @@ -134,6 +130,14 @@ def create_or_update_package_type( Raises: ValueError: If phase not found or item types are invalid """ + # Extract parameters from data dictionary + ea_act_name = data['ea_act_name'] + work_type_name = data['work_type_name'] + phase_name = data['phase_name'] + package_type_name = data['package_type_name'] + package_type_title = data['package_type_title'] + item_types = data['item_types'] + # Find the phase phase = TrackPhase.find_by_identifiers(ea_act_name, work_type_name, phase_name) if not phase: @@ -145,13 +149,13 @@ def create_or_update_package_type( # Process item types - create new ones or validate existing ones processed_item_type_ids, created_item_types = PackageTypeService._process_item_types(item_types) - # Check if package type already exists - existing_package_type = PackageType.find_by_name(package_type_name) + # Check if package type already exists for this phase + existing_package_type = PackageType.find_by_name_and_phase(package_type_name, phase.id) if existing_package_type: # Update existing package type package_type = existing_package_type - package_type.phase_id = phase.id + package_type.title = package_type_title package_type.updated_by = 'system' # TODO: Get from auth context # Remove existing item type associations @@ -160,6 +164,7 @@ def create_or_update_package_type( # Create new package type package_type = PackageType( name=package_type_name, + title=package_type_title, phase_id=phase.id, created_by='system' # TODO: Get from auth context ) @@ -176,6 +181,7 @@ def create_or_update_package_type( return { 'id': package_type.id, 'name': package_type.name, + 'title': package_type.title, 'phase_id': package_type.phase_id, 'phase_name': phase.display_name or phase.name, 'ea_act_name': phase.ea_act_name, diff --git a/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/AdditionalInformationForm.tsx b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/AdditionalInformationForm.tsx new file mode 100644 index 000000000..4c11d9eca --- /dev/null +++ b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/AdditionalInformationForm.tsx @@ -0,0 +1,44 @@ +import { + Grid, + Typography, +} from "@mui/material"; +import ControlledTextField from "@/components/Shared/ControlledFormFields/ControlledTextField"; + +export const AdditionalInformationForm = () => { + + return ( + + + + Enter the name of your submission + + + + + + + + + Enter the a brief description of your submission{" "} + + (optional) + + + + + + + + ); +}; diff --git a/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/NewAssessmentSubmissionForm.tsx b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/NewAssessmentSubmissionForm.tsx index 828597091..64911e381 100644 --- a/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/NewAssessmentSubmissionForm.tsx +++ b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/NewAssessmentSubmissionForm.tsx @@ -1,6 +1,5 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo } from "react"; import { - Box, Button, Grid, MenuItem, @@ -10,8 +9,26 @@ import { import { useNavigate, useParams } from "@tanstack/react-router"; import { useNewSubmissionStore } from "@/store/newSubmissionStore"; import { SubmissionPackageType } from "@/models/Package"; +import { AdditionalInformationForm } from "./AdditionalInformationForm"; +import { FormProvider, useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { useGetPackageTypesByPhaseId } from "@/hooks/api/usePackageTypes"; -export const NewAssessmentSubmissionForm = () => { +const additionalInfoSchema = yup.object().shape({ + name: yup.string().required("Please enter the name of your submission"), + description: yup.string().required("Please enter a description of your submission"), +}); + +type AdditionalInfoForm = yup.InferType; + +type NewAssessmentSubmissionFormProps = { + onSubmit: (data: any) => void; +}; + +export const NewAssessmentSubmissionForm = ({ + onSubmit, +}: NewAssessmentSubmissionFormProps) => { const { projectId } = useParams({ from: "/proponent/_proponentLayout/projects/$projectId/_projectLayout/new-submission", }); @@ -21,30 +38,70 @@ export const NewAssessmentSubmissionForm = () => { submissionPackageType, setSubmissionPackageType, mappedPackages, - existingIPD, + accountProject, + currentPhase, } = useNewSubmissionStore(); + // Fetch package types for the current phase + const { data: package_types = [] } = useGetPackageTypesByPhaseId({ + phaseId: currentPhase?.id, + enabled: Boolean(currentPhase?.id), + }); + const [errorText, setErrorText] = useState(null); + const [showAdditionalInfoForm, setShowAdditionalInfoForm] = useState(false); - const packages = [ - ...(!existingIPD - ? [ - { - value: SubmissionPackageType.IPD, - label: "Initial Project Description & Engagement Plan", - id: null, - }, - ] - : []), - ...mappedPackages, - { - value: SubmissionPackageType.ADDITIONAL_INFORMATION, - label: "Additional Information Submission", - id: null, + const methods = useForm({ + resolver: yupResolver(additionalInfoSchema), + mode: "onSubmit", + defaultValues: { + name: "", + description: "", }, - ]; + }); + + const { handleSubmit, reset } = methods; + + // Map package types from API to dropdown options + const packages = useMemo(() => { + return package_types.map((pkgType) => { + // Check if this package type already exists in mappedPackages + const existingPackage = mappedPackages.find( + (pkg) => pkg.value === pkgType.name + ); + + return { + value: pkgType.name as SubmissionPackageType, + label: pkgType.title || pkgType.name, + id: existingPackage?.id || null, + }; + }); + }, [package_types, mappedPackages]); + + const onSubmitAdditionalInfo = (data: AdditionalInfoForm) => { + // Get the account_project_work_id from the current phase's work + const accountProjectWorkId = + accountProject?.account_project_works?.find( + (apw) => apw.work?.current_phase?.id === currentPhase?.id + )?.id; + + // Create new package via API + onSubmit({ + name: data.name.trim(), + description: data.description?.trim() || undefined, + type: SubmissionPackageType.ADDITIONAL_INFORMATION, + account_project_work_id: accountProjectWorkId, + }); + }; const handleContinue = () => { + // If showing Additional Information form, trigger form validation and submit + if (showAdditionalInfoForm) { + handleSubmit(onSubmitAdditionalInfo)(); + return; + } + + // Handle package selection if (!submissionPackageType) { setErrorText("Please select a submission."); return; @@ -53,36 +110,77 @@ export const NewAssessmentSubmissionForm = () => { const selectedPackage = packages.find( (pkg) => pkg.value === submissionPackageType, ); + + // If package already exists, navigate to it if (selectedPackage?.id) { navigate({ to: `/proponent/projects/${projectId}/submission-packages/${selectedPackage.id}`, }); return; } - // TODO: Navigate to Additional Information Submission form (SUBMIT-761 & SUBMIT-762) + + // If it's Additional Information, show the form + if (submissionPackageType === SubmissionPackageType.ADDITIONAL_INFORMATION) { + // Form will be shown by useEffect + return; + } + + // For new package types, create the package + const selectedPackageType = package_types.find( + (pkgType) => pkgType.name === submissionPackageType + ); + + if (selectedPackageType) { + // Get the account_project_work_id from the current phase's work + const accountProjectWorkId = + accountProject?.account_project_works?.find( + (apw) => apw.work?.current_phase?.id === currentPhase?.id + )?.id; + + // Create new package via API + onSubmit({ + name: selectedPackageType.title || selectedPackageType.name, + description: undefined, + type: selectedPackageType.name, + account_project_work_id: accountProjectWorkId, + }); + } }; + const handleCancel = () => { + if (showAdditionalInfoForm) { + // Go back to package selection + setShowAdditionalInfoForm(false); + setSubmissionPackageType(null); + reset(); + return; + } navigate({ to: `/proponent/projects/${projectId}` }); }; useEffect(() => { setErrorText(null); + // Show Additional Information form immediately when selected + if (submissionPackageType === SubmissionPackageType.ADDITIONAL_INFORMATION) { + setShowAdditionalInfoForm(true); + } else { + setShowAdditionalInfoForm(false); + } }, [submissionPackageType]); return ( - - + <> + What are you submitting? - + setSubmissionPackageType(e.target.value as SubmissionPackageType) } @@ -107,23 +205,32 @@ export const NewAssessmentSubmissionForm = () => { {errorText && ( - + {errorText} )} + + {showAdditionalInfoForm && ( + + + + + + )} + - - - + + + - + ); }; diff --git a/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/index.tsx b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/index.tsx index fda6eaa75..4e39194ca 100644 --- a/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/index.tsx +++ b/submit-web/src/components/App/NewSubmission/NewAssessmentSubmission/index.tsx @@ -3,7 +3,11 @@ import { NewSubmissionCard } from "../NewSubmissionCard"; import { NewAssessmentSubmissionForm } from "./NewAssessmentSubmissionForm"; import { useNewSubmissionStore } from "@/store/newSubmissionStore"; -export function NewAssessmentSubmission() { +type NewAssessmentSubmissionProps = { + onSubmit: (data: any) => void; +}; + +export function NewAssessmentSubmission({ onSubmit }: NewAssessmentSubmissionProps) { const { accountProject } = useNewSubmissionStore(); return ( @@ -17,7 +21,7 @@ export function NewAssessmentSubmission() { } barTitle="Select Submission" > - + ); diff --git a/submit-web/src/components/App/Projects/ProjectSubmissionsCard.tsx b/submit-web/src/components/App/Projects/ProjectSubmissionsCard.tsx index c84fe5d90..980bc81fa 100644 --- a/submit-web/src/components/App/Projects/ProjectSubmissionsCard.tsx +++ b/submit-web/src/components/App/Projects/ProjectSubmissionsCard.tsx @@ -35,10 +35,10 @@ export const ProjectSubmissionsCard = ({ }: ProjectSubmissionsCardProps) => { const { userType } = useAccount(); - const activeSubmissionPackages = packages.filter( + const activeSubmissionPackages = packages?.filter( (subPackage) => !subPackage.completed_on, ); - const pastSubmissionPackages = packages.filter((subPackage) => + const pastSubmissionPackages = packages?.filter((subPackage) => Boolean(subPackage.completed_on), ); diff --git a/submit-web/src/components/App/Submission/InfoBox/index.tsx b/submit-web/src/components/App/Submission/InfoBox/index.tsx index 1cd66a261..e63c6f78f 100644 --- a/submit-web/src/components/App/Submission/InfoBox/index.tsx +++ b/submit-web/src/components/App/Submission/InfoBox/index.tsx @@ -14,7 +14,6 @@ type InfoBoxProps = { export const InfoBox = ({ submissionPackage }: InfoBoxProps) => { const { version } = submissionPackage; - const condition = useMemo(() => { if (!submissionPackage.meta) return ""; const mainCondition = get(submissionPackage, "meta.main_condition"); @@ -41,50 +40,49 @@ export const InfoBox = ({ submissionPackage }: InfoBoxProps) => { p: "16px", }} > - + - + - Submitted on: - - - {dateUtils.formatDate(submissionPackage.submitted_on) || "-"} + Condition: + {condition || "-"} - Submitted by: + Supporting Condition(s): - {submissionPackage.submitted_by || "-"} + {supportingConditions || "-"} - + - Condition: + Submitted on: + + + {dateUtils.formatDate(submissionPackage.submitted_on) || "-"} - {condition || "-"} - - Supporting Condition(s): + Submitted by: - {supportingConditions || "-"} + {submissionPackage.submitted_by || "-"} @@ -92,21 +90,25 @@ export const InfoBox = ({ submissionPackage }: InfoBoxProps) => { - - - - - - + {version && ( + <> + + + + + + + + )} ); }; diff --git a/submit-web/src/components/App/Submission/SubmissionTitle.tsx b/submit-web/src/components/App/Submission/SubmissionTitle.tsx index dd885b581..505e46bad 100644 --- a/submit-web/src/components/App/Submission/SubmissionTitle.tsx +++ b/submit-web/src/components/App/Submission/SubmissionTitle.tsx @@ -18,7 +18,6 @@ export const CardInnerBox = styled(Box)({ justifyContent: "center", flexDirection: "column", height: "100%", - padding: "0 12px", }); export const SubmissionTitle = ({ @@ -30,25 +29,43 @@ export const SubmissionTitle = ({ const { data: accountProject } = useGetAccountProject({ accountProjectId: submissionPackage?.account_project_id || 0, }); - const proponentName = accountProject?.project?.proponent?.name || ""; - const title = useMemo(() => { - return ( - customTitle || - (submissionPackage?.type.name === SubmissionPackageType.IPD - ? `${proponentName} - Assessment` - : `Management Plans & Related Documents`) - ); + if (customTitle) { + return customTitle; + } + + // Specific title rules for certain package types + if (submissionPackage?.type.name === SubmissionPackageType.IPD) { + return `${proponentName} - Assessment`; + } + + if (submissionPackage?.type.name === SubmissionPackageType.MANAGEMENT_PLAN || + submissionPackage?.type.name === SubmissionPackageType.IEM) { + return `Management Plans & Related Documents`; + } + + // Default fallback: use package type title and package name + if (submissionPackage?.type.title && submissionPackage?.name) { + return `${submissionPackage.type.title} - ${submissionPackage.name}`; + } + + // Final fallback + return submissionPackage?.name || ""; }, [submissionPackage, proponentName, customTitle]); const status = useMemo(() => { - return ( - customStatus || - (submissionPackage?.type.name === SubmissionPackageType.IPD - ? PROJECT_STATUS.EARLY_ENGAGEMENT - : PROJECT_STATUS.POST_DECISION) - ); + if (customStatus) { + return customStatus; + } + + // If package is associated with a work, show the current phase name + if (submissionPackage?.account_project_work?.work?.current_phase?.name) { + return submissionPackage.account_project_work.work.current_phase.name; + } + + // Fallback to POST_DECISION for packages without work association + return PROJECT_STATUS.POST_DECISION; }, [submissionPackage, customStatus]); return ( diff --git a/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/constants.ts b/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/constants.ts new file mode 100644 index 000000000..383c88f98 --- /dev/null +++ b/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/constants.ts @@ -0,0 +1,11 @@ +import * as yup from "yup"; + +export const additionalInformationSchema = yup.object().shape({ + uploadDocuments: yup.array().of(yup.string()), +}); + +export type AdditionalInformationForm = yup.InferType; + +export const ADDITIONAL_INFORMATION_DOCUMENT_FOLDERS = Object.freeze({ + UPLOAD_DOCUMENTS: "upload_documents", +}); diff --git a/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/index.tsx b/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/index.tsx new file mode 100644 index 000000000..d9fea1e59 --- /dev/null +++ b/submit-web/src/components/App/SubmissionItem/AdditionalInformation/ProponentView/index.tsx @@ -0,0 +1,160 @@ +import { Navigate, useNavigate, useParams } from "@tanstack/react-router"; +import { useGetAccountProject } from "@/hooks/api/useProjects"; +import { SubmissionFormContainer } from "@/components/App/SubmissionItem/SubmissionFormContainer"; +import { BCDesignTokens } from "epic.theme"; +import { SubmitLoaderBackdrop } from "@/components/Shared/Overlays/SubmitLoaderBackdrop"; +import { Grid } from "@mui/material"; +import { + GenericDocumentUploadSection, + UploadSectionConfig, +} from "@/components/App/DocumentUpload/GenericDocumentUploadSection"; +import { useMemo, useState } from "react"; +import Form from "@/components/Shared/Forms/common"; +import { FormProvider, useForm } from "react-hook-form"; +import { AdditionalInformationForm, additionalInformationSchema } from "./constants"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { useQueryClient } from "@tanstack/react-query"; +import { SubmissionItem } from "@/models/SubmissionItem"; +import { QUERY_KEY } from "@/hooks/api/constants"; +import { + SUBMISSION_ITEM_STATUS, + SUBMISSION_TYPE, + SubmissionItemStatus, +} from "@/models/Submission"; +import { S3_FOLDER } from "@/hooks/api/useObjectStorage"; +import { useSaveSubmission } from "@/hooks/api/useSubmissions"; +import { useGetSubmissionPackage } from "@/hooks/api/usePackages"; +import { notify } from "@/components/Shared/Snackbar/snackbarStore"; +import { isAxiosError } from "axios"; +import SubmissionActionButtons from "@/components/App/SubmissionItem/SubmissionActionButtons"; + +export const AdditionalInformationProponentView = () => { + const { + projectId: accountProjectIdParam, + submissionPackageId, + submissionId: submissionItemId, + } = useParams({ + from: "/proponent/_proponentLayout/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/submissions/$submissionId", + }); + + const accountProjectId = Number(accountProjectIdParam); + const { data: accountProject } = useGetAccountProject({ + accountProjectId, + }); + + const queryClient = useQueryClient(); + const submissionItem = queryClient.getQueryData([ + QUERY_KEY.SUBMISSION_ITEM, + Number(submissionItemId), + ]); + + const navigate = useNavigate(); + + const [isBackdropOpen, setIsBackdropOpen] = useState(false); + + const documentSubmissions = submissionItem?.submissions?.filter( + (submission) => submission.type === SUBMISSION_TYPE.DOCUMENT, + ); + + const defaultDocumentValues = useMemo(() => { + if (!documentSubmissions) return {}; + + return { + uploadDocuments: documentSubmissions + .filter( + (submission) => + submission.submitted_document?.folder === S3_FOLDER.UPLOAD_DOCUMENTS.value, + ) + .map((submission) => submission.submitted_document?.url), + }; + }, [documentSubmissions]); + + const methods = useForm({ + resolver: yupResolver(additionalInformationSchema), + mode: "onSubmit", + defaultValues: { + ...defaultDocumentValues, + }, + }); + + const { handleSubmit } = methods; + + const { refetch } = useGetSubmissionPackage({ + packageId: Number(submissionPackageId), + }); + + const { mutateAsync: callSaveSubmission } = useSaveSubmission({ + accountProjectId, + submissionItem, + }); + + const handleCompleteForm = (formData: AdditionalInformationForm) => { + saveSubmission(formData, SUBMISSION_ITEM_STATUS.COMPLETED.value); + }; + + const saveSubmission = async ( + _formData: AdditionalInformationForm, + status: SubmissionItemStatus, + ) => { + try { + setIsBackdropOpen(true); + await callSaveSubmission({ + data: { + type: SUBMISSION_TYPE.FORM, + status, + item_id: submissionItemId, + data: {}, + }, + }); + await refetch(); + notify.success("Submission saved successfully"); + navigate({ + to: `/proponent/projects/${accountProjectId}/submission-packages/${submissionPackageId}`, + }); + } catch (error) { + const errorMessage = + isAxiosError(error) && error.response?.data?.message + ? error.response.data.message + : "Failed to save submission"; + notify.error(errorMessage); + } finally { + setIsBackdropOpen(false); + } + }; + + const documentUploadSections: UploadSectionConfig[] = useMemo( + () => [ + { + name: "uploadDocuments", + label: "your documents", + folder: S3_FOLDER.UPLOAD_DOCUMENTS.value, + description: + "Must be unlocked PDF document (i.e., not password protected).", + }, + ], + [], + ); + + if (!accountProject) return ; + return ( + + + +
+ + + + + + +
+
+
+ ); +}; diff --git a/submit-web/src/components/App/SubmissionItem/ItemForm/ProponentItemForm.tsx b/submit-web/src/components/App/SubmissionItem/ItemForm/ProponentItemForm.tsx index bf3d0fee8..c40836149 100644 --- a/submit-web/src/components/App/SubmissionItem/ItemForm/ProponentItemForm.tsx +++ b/submit-web/src/components/App/SubmissionItem/ItemForm/ProponentItemForm.tsx @@ -12,6 +12,7 @@ import { IEMUpdateForm } from "@/components/App/SubmissionItem/IEMSubmission/IEM import { IPDSubmissionProponentView } from "@/components/App/SubmissionItem/IPDSubmission/IPDProponentView"; import { GeoSpatialProponentView } from "@/components/App/SubmissionItem/GeoSpatialInformation/GeoSpatialProponentView"; import { EngagementPlanProponentView } from "@/components/App/SubmissionItem/EPSubmission/EPProponentView"; +import { AdditionalInformationProponentView } from "@/components/App/SubmissionItem/AdditionalInformation/ProponentView"; type ItemFormProps = { submissionItem: TypeSubmissionItem; @@ -25,7 +26,7 @@ const createFormMap = { [SUBMISSION_ITEM_TYPE.IPD]: IPDSubmissionProponentView, [SUBMISSION_ITEM_TYPE.ENGAGEMENT_PLAN]: EngagementPlanProponentView, [SUBMISSION_ITEM_TYPE.GEOSPATIAL_INFORMATION]: GeoSpatialProponentView, - [SUBMISSION_ITEM_TYPE.ADDITIONAL_INFORMATION]: "", // TODO: Implement Later + [SUBMISSION_ITEM_TYPE.UPLOAD_DOCUMENT]: AdditionalInformationProponentView, }; export const ProponentItemForm = ({ submissionItem }: ItemFormProps) => { @@ -41,7 +42,7 @@ const updateFormMap = { [SUBMISSION_ITEM_TYPE.IPD]: IPDSubmissionProponentView, [SUBMISSION_ITEM_TYPE.ENGAGEMENT_PLAN]: EngagementPlanProponentView, [SUBMISSION_ITEM_TYPE.GEOSPATIAL_INFORMATION]: GeoSpatialProponentView, - [SUBMISSION_ITEM_TYPE.ADDITIONAL_INFORMATION]: "", // TODO: Implement Later + [SUBMISSION_ITEM_TYPE.UPLOAD_DOCUMENT]: AdditionalInformationProponentView, }; export const ProponentItemUpdateForm = ({ submissionItem }: ItemFormProps) => { diff --git a/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx b/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx index c57a23fbe..06e295be8 100644 --- a/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx +++ b/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx @@ -19,16 +19,25 @@ const statusStyles: Record = { }, }; +const DEFAULT_STYLE: StyleProps = { + color: "#5583B5", + label: "", +}; + type ProjectStatusProps = { status: string; }; export const ProjectStatus = ({ status }: ProjectStatusProps) => { - const style = statusStyles[status]; - - if (!style) { + if (!status) { return null; } + // Use predefined style if available, otherwise use default with the status as label + const style = statusStyles[status] || { + ...DEFAULT_STYLE, + label: status, + }; + return ( => { + return await submitRequest({ + method: "GET", + url: `staff/package-types/phase/${phaseId}`, + }); +}; + +type UseGetPackageTypesByPhaseIdParams = { + phaseId?: number; + enabled?: boolean; +}; + +export const getPackageTypesByPhaseIdQueryOptions = ({ + phaseId, + enabled = true, +}: UseGetPackageTypesByPhaseIdParams) => + queryOptions({ + queryKey: [QUERY_KEY.PACKAGE_TYPES, phaseId], + queryFn: () => getPackageTypesByPhaseId(phaseId!), + staleTime: 5 * 60 * 1000, + enabled: enabled && Boolean(phaseId), + }); + +export const useGetPackageTypesByPhaseId = ({ + phaseId, + enabled = true, +}: UseGetPackageTypesByPhaseIdParams) => { + return useQuery( + getPackageTypesByPhaseIdQueryOptions({ + phaseId, + enabled, + }) + ); +}; diff --git a/submit-web/src/models/AccountProjectWork.ts b/submit-web/src/models/AccountProjectWork.ts new file mode 100644 index 000000000..49c0c6ad0 --- /dev/null +++ b/submit-web/src/models/AccountProjectWork.ts @@ -0,0 +1,7 @@ +import { TrackWork } from "./TrackWork"; + +export type AccountProjectWork = { + id: number; + work_id: number; + work: TrackWork; +}; diff --git a/submit-web/src/models/Package.ts b/submit-web/src/models/Package.ts index cc2f36f8c..dc7322c13 100644 --- a/submit-web/src/models/Package.ts +++ b/submit-web/src/models/Package.ts @@ -1,5 +1,6 @@ import { InternalStaffDocument, SubmissionItem } from "./SubmissionItem"; import { UpdateRequest } from "./UpdateRequest"; +import { AccountProjectWork } from "./AccountProjectWork"; export enum SubmissionPackageType { MANAGEMENT_PLAN = "Management Plan", @@ -11,6 +12,7 @@ export enum SubmissionPackageType { export type PackageType = { id: number; name: SubmissionPackageType; + title?: string; }; // These statuses are just for UI purposes, the actual canonical business statuses are PackageStatus @@ -150,6 +152,7 @@ export type PackageVersion = { export type SubmissionPackage = { id: number; name: string; + description?: string; status: PackageStatus[]; submitted_on?: string; completed_on?: string; @@ -158,6 +161,7 @@ export type SubmissionPackage = { type: PackageType; items: Array; account_project_id: number; + account_project_work?: AccountProjectWork; meta?: SubmissionPackageMeta; days_since_submission?: number; internal_staff_documents?: InternalStaffDocument[]; diff --git a/submit-web/src/models/SubmissionItem.ts b/submit-web/src/models/SubmissionItem.ts index 131bfb0f0..d358e8b23 100644 --- a/submit-web/src/models/SubmissionItem.ts +++ b/submit-web/src/models/SubmissionItem.ts @@ -22,7 +22,7 @@ export enum SUBMISSION_ITEM_TYPE { IPD = "Initial Project Description", ENGAGEMENT_PLAN = "Engagement Plan", GEOSPATIAL_INFORMATION = "Geospatial Information", - ADDITIONAL_INFORMATION = "Additional Information", + UPLOAD_DOCUMENT = "Upload Files/Documents", } export const SubmissionItemTypeLabelMap = { @@ -34,7 +34,7 @@ export const SubmissionItemTypeLabelMap = { [SUBMISSION_ITEM_TYPE.IPD]: "Initial Project Description", [SUBMISSION_ITEM_TYPE.ENGAGEMENT_PLAN]: "Engagement Plan", [SUBMISSION_ITEM_TYPE.GEOSPATIAL_INFORMATION]: "Geospatial Information", - [SUBMISSION_ITEM_TYPE.ADDITIONAL_INFORMATION]: "Additional Information", + [SUBMISSION_ITEM_TYPE.UPLOAD_DOCUMENT]: "Upload Files/Documents", }; export const SUBMISSION_ITEM_MODAL_CONTENT: Record< diff --git a/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/new-submission.tsx b/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/new-submission.tsx index dcd3a9c53..8498c09fb 100644 --- a/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/new-submission.tsx +++ b/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/new-submission.tsx @@ -94,7 +94,7 @@ export function NewSubmission() { {currentPhase?.work_type_name?.toUpperCase() == WORK_TYPE_NAMES.ASSESSMENT ? ( - + ) : ( )} diff --git a/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/submissions/$submissionId.tsx b/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/submissions/$submissionId.tsx index ffc6cdf00..f351303a2 100644 --- a/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/submissions/$submissionId.tsx +++ b/submit-web/src/routes/proponent/_proponentLayout/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/submissions/$submissionId.tsx @@ -54,7 +54,6 @@ export function Submission() { const { data: submissionItem, isLoading: isItemLoading } = useSuspenseQuery( getSubmissionItemQueryOptions({ itemId: Number(subItemId) }), ); - const { data: submissionPackage, isLoading: isPackageLoading } = useSuspenseQuery( getSubmissionPackageQueryOptions({ From ac17615858cb03b6f87bd00f2ef4024f8583d93f Mon Sep 17 00:00:00 2001 From: dinesh Date: Wed, 15 Apr 2026 15:13:47 -0700 Subject: [PATCH 4/4] Additional information submission --- ...add_in_progress_status_in_package_model.py | 27 +++++++++ submit-api/src/submit_api/models/package.py | 1 + submit-api/src/submit_api/schemas/package.py | 4 ++ submit-api/src/submit_api/schemas/project.py | 1 + .../submit_api/services/invitation_service.py | 1 + .../submit_api/services/package_service.py | 14 +++++ .../App/PackageStatusChip/index.tsx | 9 +++ .../src/components/App/Projects/Project.tsx | 10 ++-- .../App/Submission/InfoBox/index.tsx | 57 +++++++++++++++---- .../App/Submission/SubmissionTitle.tsx | 19 +------ .../addProjects/ProjectStatus.tsx | 8 +-- submit-web/src/hooks/useManagementPlanName.ts | 3 + submit-web/src/models/Package.ts | 5 ++ 13 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 submit-api/migrations/versions/e77a59c88dac_add_in_progress_status_in_package_model.py diff --git a/submit-api/migrations/versions/e77a59c88dac_add_in_progress_status_in_package_model.py b/submit-api/migrations/versions/e77a59c88dac_add_in_progress_status_in_package_model.py new file mode 100644 index 000000000..acb740d72 --- /dev/null +++ b/submit-api/migrations/versions/e77a59c88dac_add_in_progress_status_in_package_model.py @@ -0,0 +1,27 @@ +"""add in_progress status in package model + +Revision ID: e77a59c88dac +Revises: d4ea378228e4 +Create Date: 2026-04-15 17:41:20.993941 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e77a59c88dac' +down_revision = 'd4ea378228e4' +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute("ALTER TYPE packagestatus ADD VALUE IF NOT EXISTS 'IN_PROGRESS';") + + +def downgrade(): + # Note: PostgreSQL does not support removing enum values directly + # This would require recreating the enum type, which is complex and risky + # If rollback is needed, it should be done manually or with a new migration + pass diff --git a/submit-api/src/submit_api/models/package.py b/submit-api/src/submit_api/models/package.py index 5dd062173..365a11721 100644 --- a/submit-api/src/submit_api/models/package.py +++ b/submit-api/src/submit_api/models/package.py @@ -44,6 +44,7 @@ class PackageStatus(enum.Enum): COMPLETED = 'COMPLETED' NEW_SUBMISSION = 'NEW_SUBMISSION' NEW = 'NEW' + IN_PROGRESS = 'IN_PROGRESS' PASSED_CONSULTATION_CHECK = 'PASSED_CONSULTATION_CHECK' FAILED_CONSULTATION_CHECK = 'FAILED_CONSULTATION_CHECK' UNDER_REVIEW = 'UNDER_REVIEW' diff --git a/submit-api/src/submit_api/schemas/package.py b/submit-api/src/submit_api/schemas/package.py index c186786b0..d6f976ab3 100644 --- a/submit-api/src/submit_api/schemas/package.py +++ b/submit-api/src/submit_api/schemas/package.py @@ -267,6 +267,10 @@ def get_package_status(status, user_type, version_obj): UserType.PROPONENT: PackageStatus.REVIEWED.value, UserType.STAFF: PackageStatus.REVIEWED.value }, + PackageStatus.IN_PROGRESS.value: { + UserType.PROPONENT: PackageStatus.IN_PROGRESS.value, + UserType.STAFF: PackageStatus.IN_PROGRESS.value + }, } if status in package_status_mapping: diff --git a/submit-api/src/submit_api/schemas/project.py b/submit-api/src/submit_api/schemas/project.py index a6117c03f..9a7d6432c 100644 --- a/submit-api/src/submit_api/schemas/project.py +++ b/submit-api/src/submit_api/schemas/project.py @@ -9,6 +9,7 @@ from submit_api.schemas.package import PackageSchema, StaffPackageSchema from submit_api.schemas.proponent import ProponentSchema from submit_api.schemas.account_project_work import AccountProjectWorkSchema +from submit_api.schemas.track_work import TrackWorkSchema class ProjectSchema(Schema): diff --git a/submit-api/src/submit_api/services/invitation_service.py b/submit-api/src/submit_api/services/invitation_service.py index 69664b79b..4acf5808d 100644 --- a/submit-api/src/submit_api/services/invitation_service.py +++ b/submit-api/src/submit_api/services/invitation_service.py @@ -226,6 +226,7 @@ def accept_invitation(token, payload): # pylint: disable=too-many-locals account_project_works.append(account_project_work) # Create default submission package (if required by EAO) + # This portion needs to be revisited to work for any phase, not just Early Engagement if any( apw.work.is_in_specific_phase('Early Engagement', WorkTypeName.ASSESSMENT) for apw in account_project_works diff --git a/submit-api/src/submit_api/services/package_service.py b/submit-api/src/submit_api/services/package_service.py index 46fb4c231..f3f40eea7 100644 --- a/submit-api/src/submit_api/services/package_service.py +++ b/submit-api/src/submit_api/services/package_service.py @@ -97,6 +97,12 @@ def _create_package(session, account_project_id, request_data, package_type): # Use account_project_work_id from request if provided if request_data.get("account_project_work_id"): package_data["account_project_work_id"] = request_data.get("account_project_work_id") + # Set IN_PROGRESS status for work-related packages + if not package_data.get("status"): + package_data["status"] = [PackageStatus.IN_PROGRESS.value] + current_app.logger.info( + f"Setting IN_PROGRESS status for work-related package with work_id: {request_data.get('account_project_work_id')}" + ) current_app.logger.info( f"Using account_project_work_id from request: {request_data.get('account_project_work_id')}" ) @@ -394,6 +400,14 @@ def submit_package(cls, package_id): @classmethod def _submit_package(cls, package, session): """Submit the package by updating its status and items.""" + # For work-related packages with IN_PROGRESS status, explicitly set to SUBMITTED + if package.account_project_work_id and PackageStatus.IN_PROGRESS.value in package.status: + package.status = [PackageStatus.SUBMITTED.value] + session.add(package) + current_app.logger.info( + f"Changed status from IN_PROGRESS to SUBMITTED for work-related package {package.id}" + ) + cls._update_items_status( package.items, ItemStatus.SUBMITTED.value, session) cls._update_package_status(package.id, session, package) diff --git a/submit-web/src/components/App/PackageStatusChip/index.tsx b/submit-web/src/components/App/PackageStatusChip/index.tsx index d101c4caf..830c53c2e 100644 --- a/submit-web/src/components/App/PackageStatusChip/index.tsx +++ b/submit-web/src/components/App/PackageStatusChip/index.tsx @@ -115,6 +115,15 @@ const statusStyles: Record< }, label: "New", }, + IN_PROGRESS: { + sx: { + borderRadius: 1, + border: `1px solid ${BCDesignTokens.themeBlue100}`, + background: BCDesignTokens.themeBlue20, + height: "24px", + }, + label: "In Progress", + }, NEW_SUBMISSION: { sx: { borderRadius: 1, diff --git a/submit-web/src/components/App/Projects/Project.tsx b/submit-web/src/components/App/Projects/Project.tsx index c9e2babaf..64ca34fae 100644 --- a/submit-web/src/components/App/Projects/Project.tsx +++ b/submit-web/src/components/App/Projects/Project.tsx @@ -10,10 +10,10 @@ type ProjectParam = { export const Project = ({ accountProject }: ProjectParam) => { const navigate = useNavigate(); - const { name, ea_certificate } = accountProject.project; - const currentPhase = - accountProject.account_project_works?.at(-1)?.work?.current_phase ?? null; + const currentWork = + accountProject.account_project_works?.at(-1)?.work ?? null; + const currentPhase = currentWork?.current_phase ?? null; const handleNewSubmission = () => { navigate({ @@ -30,8 +30,8 @@ export const Project = ({ accountProject }: ProjectParam) => { > {currentPhase?.work_type_name?.toUpperCase() == "ASSESSMENT" ? ( diff --git a/submit-web/src/components/App/Submission/InfoBox/index.tsx b/submit-web/src/components/App/Submission/InfoBox/index.tsx index e63c6f78f..3b6849690 100644 --- a/submit-web/src/components/App/Submission/InfoBox/index.tsx +++ b/submit-web/src/components/App/Submission/InfoBox/index.tsx @@ -32,15 +32,51 @@ export const InfoBox = ({ submissionPackage }: InfoBoxProps) => { }, [submissionPackage]); return ( - - + <> + {submissionPackage.description && ( + + + Description:  
+
+ + {submissionPackage.description} + +
+ )} + + @@ -109,6 +145,7 @@ export const InfoBox = ({ submissionPackage }: InfoBoxProps) => { )} - + + ); }; diff --git a/submit-web/src/components/App/Submission/SubmissionTitle.tsx b/submit-web/src/components/App/Submission/SubmissionTitle.tsx index 505e46bad..72569bd8e 100644 --- a/submit-web/src/components/App/Submission/SubmissionTitle.tsx +++ b/submit-web/src/components/App/Submission/SubmissionTitle.tsx @@ -2,7 +2,6 @@ import { SubmissionPackage, SubmissionPackageType } from "@/models/Package"; import { Box, styled, SxProps, Typography } from "@mui/material"; import { ProjectStatus } from "@/components/App/registration/addProjects/ProjectStatus"; import { PROJECT_STATUS } from "@/components/App/registration/addProjects/ProjectCard/constants"; -import { useGetAccountProject } from "@/hooks/api/useProjects"; import { useMemo } from "react"; type SubmissionTitleProps = { @@ -26,33 +25,19 @@ export const SubmissionTitle = ({ customTitle, customStatus, }: SubmissionTitleProps) => { - const { data: accountProject } = useGetAccountProject({ - accountProjectId: submissionPackage?.account_project_id || 0, - }); - const proponentName = accountProject?.project?.proponent?.name || ""; const title = useMemo(() => { if (customTitle) { return customTitle; } - // Specific title rules for certain package types - if (submissionPackage?.type.name === SubmissionPackageType.IPD) { - return `${proponentName} - Assessment`; - } - if (submissionPackage?.type.name === SubmissionPackageType.MANAGEMENT_PLAN || submissionPackage?.type.name === SubmissionPackageType.IEM) { return `Management Plans & Related Documents`; } - // Default fallback: use package type title and package name - if (submissionPackage?.type.title && submissionPackage?.name) { - return `${submissionPackage.type.title} - ${submissionPackage.name}`; - } - // Final fallback - return submissionPackage?.name || ""; - }, [submissionPackage, proponentName, customTitle]); + return submissionPackage?.account_project_work?.work?.title || ""; + }, [submissionPackage, customTitle]); const status = useMemo(() => { if (customStatus) { diff --git a/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx b/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx index 21f69a9f7..a4bbac4dc 100644 --- a/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx +++ b/submit-web/src/components/App/registration/addProjects/ProjectStatus.tsx @@ -8,10 +8,6 @@ type StyleProps = { label: string; }; -// const DEFAULT_STYLE: StyleProps = { -// color: EAOColors.ProponentDark, -// label: "Unknown Status", -// }; const statusStyles: Record = { POST_DECISION: { @@ -33,9 +29,7 @@ type ProjectStatusProps = { status: string; }; export const ProjectStatus = ({ status }: ProjectStatusProps) => { - if (!status) { - return null; - } + // Use predefined style if available, otherwise use default with the status as label const style = statusStyles[status] || { diff --git a/submit-web/src/hooks/useManagementPlanName.ts b/submit-web/src/hooks/useManagementPlanName.ts index fe929ddca..fee3f77eb 100644 --- a/submit-web/src/hooks/useManagementPlanName.ts +++ b/submit-web/src/hooks/useManagementPlanName.ts @@ -26,6 +26,9 @@ export const useManagementPlanName = ( if (needsConditionNumber && conditionNumber) { return conditionNumber + " - " + submissionPackage.name; } + if (submissionPackage.type.name === SubmissionPackageType.ADDITIONAL_INFORMATION) { + return `${submissionPackage.type.title} - ${submissionPackage.name}`; + } return submissionPackage.name; }, [submissionPackage]); }; diff --git a/submit-web/src/models/Package.ts b/submit-web/src/models/Package.ts index dc7322c13..db219f017 100644 --- a/submit-web/src/models/Package.ts +++ b/submit-web/src/models/Package.ts @@ -49,6 +49,7 @@ export type PackageStatus = | "PARTIALLY_COMPLETED" | "NEW_SUBMISSION" | "NEW" + | "IN_PROGRESS" | "UNDER_CONSULTATION_CHECK" | "PASSED_CONSULTATION_CHECK" | "AWAITING_MANAGER_APPROVAL" @@ -96,6 +97,10 @@ export const PACKAGE_STATUS: Record< value: "NEW", label: "New", }, + IN_PROGRESS: { + value: "IN_PROGRESS", + label: "In Progress", + }, NEW_SUBMISSION: { value: "NEW_SUBMISSION", label: "New Submission",