From a2941c1d3650fefb3980d3a41ca06cece9793cb0 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Mon, 5 Aug 2024 21:22:37 -0700 Subject: [PATCH 01/26] Adds new type of document set recentEntryReview with associated schema and endpoints --- .../database/patient/recent_entry_reviews.py | 73 ++++ scope_shared/scope/schema.py | 4 + scope_shared/scope/schemas/document.json | 3 + .../documents/recent-entry-review.json | 35 ++ .../documents/recent-entry-reviews.json | 9 + scope_shared/scope/testing/__init__.py | 2 + .../fixtures_fake_recent_entry_review.py | 75 ++++ .../fixtures_fake_recent_entry_reviews.py | 51 +++ .../test_schemas/test_fake_data_schemas.py | 36 +- server_flask/app.py | 5 + server_flask/blueprints/registry/patients.py | 15 +- .../registry/recent_entry_reviews.py | 158 ++++++++ .../test_flask/registry/test_patient_set.py | 374 +++++++++--------- 13 files changed, 650 insertions(+), 190 deletions(-) create mode 100644 scope_shared/scope/database/patient/recent_entry_reviews.py create mode 100644 scope_shared/scope/schemas/documents/recent-entry-review.json create mode 100644 scope_shared/scope/schemas/documents/recent-entry-reviews.json create mode 100644 scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py create mode 100644 scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py create mode 100644 server_flask/blueprints/registry/recent_entry_reviews.py diff --git a/scope_shared/scope/database/patient/recent_entry_reviews.py b/scope_shared/scope/database/patient/recent_entry_reviews.py new file mode 100644 index 000000000..b5a453c82 --- /dev/null +++ b/scope_shared/scope/database/patient/recent_entry_reviews.py @@ -0,0 +1,73 @@ +from typing import List, Optional + +import pymongo.collection +import scope.database.collection_utils + +DOCUMENT_TYPE = "recentEntryReview" +SEMANTIC_SET_ID = "recentEntryReviewId" + + +def get_recent_entry_reviews( + *, + collection: pymongo.collection.Collection, +) -> Optional[List[dict]]: + """ + Get list of "recentEntryReview" documents. + """ + + return scope.database.collection_utils.get_set( + collection=collection, + document_type=DOCUMENT_TYPE, + ) + + +def get_recent_entry_review( + *, + collection: pymongo.collection.Collection, + set_id: str, +) -> Optional[dict]: + """ + Get "recentEntryReview" document. + """ + + return scope.database.collection_utils.get_set_element( + collection=collection, + document_type=DOCUMENT_TYPE, + set_id=set_id, + ) + + +def post_recent_entry_review( + *, + collection: pymongo.collection.Collection, + recent_entry_review: dict, +) -> scope.database.collection_utils.SetPostResult: + """ + Post "recentEntryReview" document. + """ + + return scope.database.collection_utils.post_set_element( + collection=collection, + document_type=DOCUMENT_TYPE, + semantic_set_id=SEMANTIC_SET_ID, + document=recent_entry_review, + ) + + +def put_recent_entry_review( + *, + collection: pymongo.collection.Collection, + recent_entry_review: dict, + set_id: str, +) -> scope.database.collection_utils.SetPutResult: + """ + Put "recentEntryReview" document. + """ + + return scope.database.collection_utils.put_set_element( + collection=collection, + document_type=DOCUMENT_TYPE, + semantic_set_id=SEMANTIC_SET_ID, + set_id=set_id, + document=recent_entry_review, + ) diff --git a/scope_shared/scope/schema.py b/scope_shared/scope/schema.py index 54778a836..dfc973eb9 100644 --- a/scope_shared/scope/schema.py +++ b/scope_shared/scope/schema.py @@ -42,6 +42,8 @@ provider_identities_schema: Optional[jschon.JSONSchema] = None referral_status_schema: Optional[jschon.JSONSchema] = None regexes: Optional[jschon.JSONSchema] = None +recent_entry_review_schema: Optional[jschon.JSONSchema] = None +recent_entry_reviews_schema: Optional[jschon.JSONSchema] = None resource_content_schema: Optional[jschon.JSONSchema] = None resource_contents_schema: Optional[jschon.JSONSchema] = None safety_plan_schema: Optional[jschon.JSONSchema] = None @@ -100,6 +102,8 @@ "patient_profile_schema": "documents/patient-profile.json", "provider_identity_schema": "documents/provider-identity.json", "provider_identities_schema": "documents/provider-identities.json", + "recent_entry_review_schema": "documents/recent-entry-review.json", + "recent_entry_reviews_schema": "documents/recent-entry-reviews.json", "safety_plan_schema": "documents/safety-plan.json", "scheduled_activity_schema": "documents/scheduled-activity.json", "scheduled_activities_schema": "documents/scheduled-activities.json", diff --git a/scope_shared/scope/schemas/document.json b/scope_shared/scope/schemas/document.json index d59514eed..4357ca015 100644 --- a/scope_shared/scope/schemas/document.json +++ b/scope_shared/scope/schemas/document.json @@ -36,6 +36,9 @@ { "$ref": "/schemas/documents/patient-profile" }, + { + "$ref": "/schemas/documents/recent-entry-review" + }, { "$ref": "/schemas/documents/safety-plan" }, diff --git a/scope_shared/scope/schemas/documents/recent-entry-review.json b/scope_shared/scope/schemas/documents/recent-entry-review.json new file mode 100644 index 000000000..9b6c20e5a --- /dev/null +++ b/scope_shared/scope/schemas/documents/recent-entry-review.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://uwscope.org/schemas/documents/recent-entry-review", + "title": "IRecentEntryReview", + "description": "IRecentEntryReview Type", + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "_type": { + "const": "recentEntryReview" + }, + "_set_id": { + "type": "string" + }, + "_rev": { + "type": "number" + }, + "recentEntryReviewId": { + "type": "string" + }, + "editedDateTime": { + "$ref": "/schemas/utils/datetime#/properties/datetime" + }, + "effectiveDateTime": { + "$ref": "/schemas/utils/datetime#/properties/datetime" + }, + "providerName": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["_type", "editedDateTime", "effectiveDateTime", "providerName"] +} diff --git a/scope_shared/scope/schemas/documents/recent-entry-reviews.json b/scope_shared/scope/schemas/documents/recent-entry-reviews.json new file mode 100644 index 000000000..2df4b4c27 --- /dev/null +++ b/scope_shared/scope/schemas/documents/recent-entry-reviews.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://uwscope.org/schemas/documents/recent-entry-reviews", + "title": "IRecentEntryReview[]", + "type": "array", + "items": { + "$ref": "/schemas/documents/recent-entry-review" + } +} diff --git a/scope_shared/scope/testing/__init__.py b/scope_shared/scope/testing/__init__.py index edc40c698..d06b42e49 100644 --- a/scope_shared/scope/testing/__init__.py +++ b/scope_shared/scope/testing/__init__.py @@ -20,6 +20,8 @@ "scope.testing.fake_data.fixtures_fake_patient_profile", "scope.testing.fake_data.fixtures_fake_provider_identity", "scope.testing.fake_data.fixtures_fake_referral_status", + "scope.testing.fake_data.fixtures_fake_recent_entry_review", + "scope.testing.fake_data.fixtures_fake_recent_entry_reviews", "scope.testing.fake_data.fixtures_fake_safety_plan", "scope.testing.fake_data.fixtures_fake_session", "scope.testing.fake_data.fixtures_fake_sessions", diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py new file mode 100644 index 000000000..afb7a72d7 --- /dev/null +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py @@ -0,0 +1,75 @@ +import datetime +import faker +import pytest +import pytz +import random +from typing import Callable + +import scope.database.date_utils as date_utils +import scope.database.patient.recent_entry_reviews +import scope.enums +import scope.schema +import scope.schema_utils +import scope.testing.fake_data.fake_utils as fake_utils + + +def fake_recent_entry_review_factory( + *, + faker_factory: faker.Faker, +) -> Callable[[], dict]: + """ + Obtain a factory that will generate fake recent entry review documents. + """ + + def factory() -> dict: + fake_recent_entry_review = { + "_type": scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE, + "editedDateTime": date_utils.format_datetime( + pytz.utc.localize( + faker_factory.date_time_between_dates( + datetime_start=datetime.datetime.now() + - datetime.timedelta(weeks=1), + datetime_end=datetime.datetime.now(), + ) + ) + ), + "effectiveDateTime": date_utils.format_datetime( + pytz.utc.localize( + faker_factory.date_time_between_dates( + datetime_start=datetime.datetime.now() + - datetime.timedelta(weeks=2), + datetime_end=datetime.datetime.now(), + ) + ) + ), + "providerName": faker_factory.name(), + } + + return fake_recent_entry_review + + return factory + + +@pytest.fixture(name="data_fake_recent_entry_review_factory") +def fixture_data_fake_recent_entry_review_factory( + faker: faker.Faker, +) -> Callable[[], dict]: + """ + Fixture for data_fake_recent_entry_review_factory. + """ + + unvalidated_factory = fake_recent_entry_review_factory( + faker_factory=faker, + ) + + def factory() -> dict: + fake_recent_entry = unvalidated_factory() + + scope.schema_utils.xfail_for_invalid_schema( + schema=scope.schema.recent_entry_review_schema, + data=fake_recent_entry, + ) + + return fake_recent_entry + + return factory diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py new file mode 100644 index 000000000..45e51bc7b --- /dev/null +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py @@ -0,0 +1,51 @@ +import pytest +import random +from typing import Callable, List + +import scope.database.document_utils as document_utils +import scope.schema +import scope.schema_utils +import scope.testing.fake_data.fake_utils as fake_utils + + +def fake_recent_entry_reviews_factory( + *, + fake_recent_entry_review_factory: Callable[[], dict], +) -> Callable[[], List[dict]]: + """ + Obtain a factory that will generate a list of fake recent entry review documents. + """ + + def factory() -> List[dict]: + fake_recent_entry_reviews = [ + fake_recent_entry_review_factory() for _ in range(random.randint(1, 5)) + ] + + return fake_recent_entry_reviews + + return factory + + +@pytest.fixture(name="data_fake_recent_entry_reviews_factory") +def fixture_data_fake_recent_entry_reviews_factory( + data_fake_recent_entry_review_factory: Callable[[], dict], +) -> Callable[[], List[dict]]: + """ + Fixture for data_fake_recent_entry_reviews_factory. + """ + + unvalidated_factory = fake_recent_entry_reviews_factory( + fake_recent_entry_review_factory=data_fake_recent_entry_review_factory, + ) + + def factory() -> List[dict]: + fake_recent_entry_reviews = unvalidated_factory() + + scope.schema_utils.xfail_for_invalid_schema( + schema=scope.schema.recent_entry_reviews_schema, + data=fake_recent_entry_reviews, + ) + + return fake_recent_entry_reviews + + return factory diff --git a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py index adc483ae1..b4c843963 100644 --- a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py +++ b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py @@ -13,7 +13,7 @@ import scope.database.patient.assessments import scope.database.patient.case_reviews import scope.database.patient.mood_logs -import scope.database.patient.sessions +import scope.database.patient.recent_entry_reviews import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments import scope.database.patient.sessions @@ -38,6 +38,8 @@ import scope.testing.fake_data.fixtures_fake_mood_logs import scope.testing.fake_data.fixtures_fake_patient_profile import scope.testing.fake_data.fixtures_fake_provider_identity +import scope.testing.fake_data.fixtures_fake_recent_entry_review +import scope.testing.fake_data.fixtures_fake_recent_entry_reviews import scope.testing.fake_data.fixtures_fake_referral_status import scope.testing.fake_data.fixtures_fake_safety_plan import scope.testing.fake_data.fixtures_fake_session @@ -270,6 +272,26 @@ class ConfigTestFakeDataSchema: expected_semantic_set_id=scope.database.providers.PROVIDER_IDENTITY_SEMANTIC_SET_ID, expected_set_ids=None, ), + ConfigTestFakeDataSchema( + name="recent-entry-review", + schema=scope.schema.recent_entry_review_schema, + data_factory_fixture="data_fake_recent_entry_review_factory", + expected_document=True, + expected_singleton=False, + expected_set_element=True, + expected_semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + expected_set_ids=None, + ), + ConfigTestFakeDataSchema( + name="recent-entry-reviews", + schema=scope.schema.recent_entry_reviews_schema, + data_factory_fixture="data_fake_recent_entry_reviews_factory", + expected_document=False, + expected_singleton=False, + expected_set_element=False, + expected_semantic_set_id=None, + expected_set_ids=None, + ), ConfigTestFakeDataSchema( name="referral-status", schema=scope.schema.referral_status_schema, @@ -486,9 +508,9 @@ def test_fake_data_schema( == document_set_element["_set_id"] ) else: - document_set_element[ - config.expected_semantic_set_id - ] = document_set_element["_set_id"] + document_set_element[config.expected_semantic_set_id] = ( + document_set_element["_set_id"] + ) else: assert "_set_id" not in document_set_element document_set_element["_set_id"] = collection_utils.generate_set_id() @@ -497,9 +519,9 @@ def test_fake_data_schema( assert ( config.expected_semantic_set_id not in document_set_element ) - document_set_element[ - config.expected_semantic_set_id - ] = document_set_element["_set_id"] + document_set_element[config.expected_semantic_set_id] = ( + document_set_element["_set_id"] + ) document_set_element = document_utils.normalize_document( document=document_set_element diff --git a/server_flask/app.py b/server_flask/app.py index 051d85902..f369e520c 100644 --- a/server_flask/app.py +++ b/server_flask/app.py @@ -19,6 +19,7 @@ import blueprints.registry.patient_profile import blueprints.registry.patients import blueprints.registry.providers +import blueprints.registry.recent_entry_reviews import blueprints.registry.safety_plan import blueprints.registry.sessions import blueprints.registry.scheduled_activities @@ -149,6 +150,10 @@ def status(): blueprints.registry.values.values_blueprint, url_prefix="/patient/", ) + app.register_blueprint( + blueprints.registry.recent_entry_reviews.recent_entry_reviews_blueprint, + url_prefix="/patient/", + ) # # Register all the `patient` blueprints, i.e. blueprints for web_patient # patient = Blueprint("patient", __name__, url_prefix="/patient") diff --git a/server_flask/blueprints/registry/patients.py b/server_flask/blueprints/registry/patients.py index 98c769e91..a67253dcc 100644 --- a/server_flask/blueprints/registry/patients.py +++ b/server_flask/blueprints/registry/patients.py @@ -15,6 +15,7 @@ import scope.database.patient.clinical_history import scope.database.patient.mood_logs import scope.database.patient.patient_profile +import scope.database.patient.recent_entry_reviews import scope.database.patient.safety_plan import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments @@ -58,6 +59,7 @@ def _construct_patient_document( scope.database.patient.assessment_logs.DOCUMENT_TYPE, scope.database.patient.case_reviews.DOCUMENT_TYPE, scope.database.patient.mood_logs.DOCUMENT_TYPE, + scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE, scope.database.patient.scheduled_activities.DOCUMENT_TYPE, scope.database.patient.sessions.DOCUMENT_TYPE, scope.database.patient.values.DOCUMENT_TYPE, @@ -109,6 +111,11 @@ def _construct_patient_document( scope.database.patient.patient_profile.DOCUMENT_TYPE ] + # Recent Entry Reviews + patient_document["recentEntryReviews"] = documents_by_type[ + scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE + ] + # Safety Plan patient_document["safetyPlan"] = documents_by_type[ scope.database.patient.safety_plan.DOCUMENT_TYPE @@ -116,10 +123,10 @@ def _construct_patient_document( # Scheduled Assessments # TODO: this access currently modifies documents, cannot be replaced - patient_document[ - "scheduledAssessments" - ] = scope.database.patient.scheduled_assessments.get_scheduled_assessments( - collection=patient_collection + patient_document["scheduledAssessments"] = ( + scope.database.patient.scheduled_assessments.get_scheduled_assessments( + collection=patient_collection + ) ) # Scheduled Activities diff --git a/server_flask/blueprints/registry/recent_entry_reviews.py b/server_flask/blueprints/registry/recent_entry_reviews.py new file mode 100644 index 000000000..83063db8c --- /dev/null +++ b/server_flask/blueprints/registry/recent_entry_reviews.py @@ -0,0 +1,158 @@ +import flask +import flask_json +import pymongo.errors + +import request_context +import request_utils +import scope.database +import scope.database.patient.recent_entry_reviews +import scope.schema + +recent_entry_reviews_blueprint = flask.Blueprint( + "recent_entry_reviews_blueprint", + __name__, +) + + +@recent_entry_reviews_blueprint.route( + "//recententryreviews", + methods=["GET"], +) +@flask_json.as_json +def get_recent_entry_reviews(patient_id): + context = request_context.authorized_for_patient(patient_id=patient_id) + patient_collection = context.patient_collection(patient_id=patient_id) + + documents = scope.database.patient.recent_entry_reviews.get_recent_entry_reviews( + collection=patient_collection, + ) + + # Validate and normalize the response + documents = request_utils.set_get_response_validate( + documents=documents, + ) + + return { + "recententryreviews": documents, + } + + +@recent_entry_reviews_blueprint.route( + "//recententryreviews", + methods=["POST"], +) +@request_utils.validate_schema( + schema=scope.schema.recent_entry_review_schema, + key="recententryreview", +) +@flask_json.as_json +def post_recent_entry_reviews(patient_id): + context = request_context.authorized_for_patient(patient_id=patient_id) + patient_collection = context.patient_collection(patient_id=patient_id) + + # Obtain the document being put + document = flask.request.json["recententryreview"] + + # Validate and normalize the request + document = request_utils.set_post_request_validate( + semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + document=document, + ) + + # Store the document + result = scope.database.patient.recent_entry_reviews.post_recent_entry_review( + collection=patient_collection, + recent_entry_review=document, + ) + + # Validate and normalize the response + document_response = request_utils.set_post_response_validate( + document=result.document, + ) + + return { + "recententryreview": document_response, + } + + +@recent_entry_reviews_blueprint.route( + "//recententryreview/", + methods=["GET"], +) +@flask_json.as_json +def get_recent_entry_review(patient_id, recententryreview_id): + context = request_context.authorized_for_patient(patient_id=patient_id) + patient_collection = context.patient_collection(patient_id=patient_id) + + # Get the document + document = scope.database.patient.recent_entry_reviews.get_recent_entry_review( + collection=patient_collection, + set_id=recententryreview_id, + ) + + # Validate and normalize the response + document = request_utils.singleton_get_response_validate( + document=document, + ) + + return { + "recententryreview": document, + } + + +@recent_entry_reviews_blueprint.route( + "//recententryreview/", + methods=["PUT"], +) +@request_utils.validate_schema( + schema=scope.schema.recent_entry_review_schema, + key="recententryreview", +) +@flask_json.as_json +def put_recent_entry_review(patient_id, recententryreview_id): + context = request_context.authorized_for_patient(patient_id=patient_id) + patient_collection = context.patient_collection(patient_id=patient_id) + + # Obtain the document being put + document = flask.request.json["recententryreview"] + + # Validate and normalize the request + document = request_utils.set_element_put_request_validate( + semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + document=document, + set_id=recententryreview_id, + ) + + # Store the document + try: + result = scope.database.patient.recent_entry_reviews.put_recent_entry_review( + collection=patient_collection, + recent_entry_review=document, + set_id=recententryreview_id, + ) + except pymongo.errors.DuplicateKeyError: + # Indicates a revision race condition, return error with current revision + document_conflict = ( + scope.database.patient.recent_entry_reviews.get_recent_entry_review( + collection=patient_collection, set_id=recententryreview_id + ) + ) + # Validate and normalize the response + document_conflict = request_utils.singleton_put_response_validate( + document=document_conflict + ) + + request_utils.abort_revision_conflict( + document={ + "recententryreview": document_conflict, + } + ) + else: + # Validate and normalize the response + document_response = request_utils.singleton_put_response_validate( + document=result.document, + ) + + return { + "recententryreview": document_response, + } diff --git a/server_flask/tests/test_flask/registry/test_patient_set.py b/server_flask/tests/test_flask/registry/test_patient_set.py index c03f94d04..c765623a2 100644 --- a/server_flask/tests/test_flask/registry/test_patient_set.py +++ b/server_flask/tests/test_flask/registry/test_patient_set.py @@ -16,6 +16,7 @@ import scope.database.patient.assessment_logs import scope.database.patient.case_reviews import scope.database.patient.mood_logs +import scope.database.patient.recent_entry_reviews import scope.database.patient.sessions import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments @@ -76,188 +77,203 @@ class ConfigTestPatientSet: TEST_CONFIGS = [ + # ConfigTestPatientSet( + # name="activities", + # semantic_set_id=scope.database.patient.activities.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_activity_factory", + # document_factory_fixture_set="data_fake_activities_factory", + # database_get_set_function=scope.database.patient.activities.get_activities, + # database_get_function=scope.database.patient.activities.get_activity, + # database_post_function=scope.database.patient.activities.post_activity, + # database_unsafe_update_function=None, + # database_document_parameter_name="activity", + # flask_query_set_type="activities", + # flask_document_set_key="activities", + # flask_query_set_element_type="activity", + # flask_document_set_element_key="activity", + # options=ConfigTestPatientSetOptions( + # set_supports_deletion=True, + # ), + # ), + # ConfigTestPatientSet( + # name="activitylogs", + # semantic_set_id=scope.database.patient.activity_logs.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_activity_log_factory", + # document_factory_fixture_set="data_fake_activity_logs_factory", + # database_get_set_function=scope.database.patient.activity_logs.get_activity_logs, + # database_get_function=scope.database.patient.activity_logs.get_activity_log, + # database_post_function=scope.database.patient.activity_logs.post_activity_log, + # database_unsafe_update_function=None, + # database_document_parameter_name="activity_log", + # flask_query_set_type="activitylogs", + # flask_document_set_key="activitylogs", + # flask_query_set_element_type="activitylog", + # flask_document_set_element_key="activitylog", + # ), + # ConfigTestPatientSet( + # name="activityschedules", + # semantic_set_id=scope.database.patient.activity_schedules.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_activity_schedule_factory", + # document_factory_fixture_set="data_fake_activity_schedules_factory", + # database_get_set_function=scope.database.patient.activity_schedules.get_activity_schedules, + # database_get_function=scope.database.patient.activity_schedules.get_activity_schedule, + # database_post_function=scope.database.patient.activity_schedules.post_activity_schedule, + # database_unsafe_update_function=None, + # database_document_parameter_name="activity_schedule", + # flask_query_set_type="activityschedules", + # flask_document_set_key="activityschedules", + # flask_query_set_element_type="activityschedule", + # flask_document_set_element_key="activityschedule", + # options=ConfigTestPatientSetOptions( + # set_supports_deletion=True, + # ), + # ), + # ConfigTestPatientSet( + # name="assessments", + # semantic_set_id=scope.database.patient.assessments.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_assessment_factory", + # document_factory_fixture_set="data_fake_assessments_factory", + # database_get_set_function=scope.database.patient.assessments.get_assessments, + # database_get_function=scope.database.patient.assessments.get_assessment, + # database_post_function=None, # Assessments have fixed set IDs + # database_unsafe_update_function=scope.database.patient_unsafe_utils.unsafe_update_assessment, + # database_document_parameter_name="assessment", + # flask_query_set_type="assessments", + # flask_document_set_key="assessments", + # flask_query_set_element_type="assessment", + # flask_document_set_element_key="assessment", + # options=ConfigTestPatientSetOptions( + # set_id_will_already_exist=True, + # set_element_will_already_exist=True, + # ), + # ), + # ConfigTestPatientSet( + # name="assessmentlogs", + # semantic_set_id=scope.database.patient.assessment_logs.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_assessment_log_factory", + # document_factory_fixture_set="data_fake_assessment_logs_factory", + # database_get_set_function=scope.database.patient.assessment_logs.get_assessment_logs, + # database_get_function=scope.database.patient.assessment_logs.get_assessment_log, + # database_post_function=scope.database.patient.assessment_logs.post_assessment_log, + # database_unsafe_update_function=None, + # database_document_parameter_name="assessment_log", + # flask_query_set_type="assessmentlogs", + # flask_document_set_key="assessmentlogs", + # flask_query_set_element_type="assessmentlog", + # flask_document_set_element_key="assessmentlog", + # ), + # ConfigTestPatientSet( + # name="casereviews", + # semantic_set_id=scope.database.patient.case_reviews.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_case_review_factory", + # document_factory_fixture_set="data_fake_case_reviews_factory", + # database_get_set_function=scope.database.patient.case_reviews.get_case_reviews, + # database_get_function=scope.database.patient.case_reviews.get_case_review, + # database_post_function=scope.database.patient.case_reviews.post_case_review, + # database_unsafe_update_function=None, + # database_document_parameter_name="case_review", + # flask_query_set_type="casereviews", + # flask_document_set_key="casereviews", + # flask_query_set_element_type="casereview", + # flask_document_set_element_key="casereview", + # ), + # ConfigTestPatientSet( + # name="moodlogs", + # semantic_set_id=scope.database.patient.mood_logs.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_mood_log_factory", + # document_factory_fixture_set="data_fake_mood_logs_factory", + # database_get_set_function=scope.database.patient.mood_logs.get_mood_logs, + # database_get_function=scope.database.patient.mood_logs.get_mood_log, + # database_post_function=scope.database.patient.mood_logs.post_mood_log, + # database_unsafe_update_function=None, + # database_document_parameter_name="mood_log", + # flask_query_set_type="moodlogs", + # flask_document_set_key="moodlogs", + # flask_query_set_element_type="moodlog", + # flask_document_set_element_key="moodlog", + # ), ConfigTestPatientSet( - name="activities", - semantic_set_id=scope.database.patient.activities.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_activity_factory", - document_factory_fixture_set="data_fake_activities_factory", - database_get_set_function=scope.database.patient.activities.get_activities, - database_get_function=scope.database.patient.activities.get_activity, - database_post_function=scope.database.patient.activities.post_activity, + name="recententryreviews", + semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_recent_entry_review_factory", + document_factory_fixture_set="data_fake_recent_entry_reviews_factory", + database_get_set_function=scope.database.patient.recent_entry_reviews.get_recent_entry_reviews, + database_get_function=scope.database.patient.recent_entry_reviews.get_recent_entry_review, + database_post_function=scope.database.patient.recent_entry_reviews.post_recent_entry_review, database_unsafe_update_function=None, - database_document_parameter_name="activity", - flask_query_set_type="activities", - flask_document_set_key="activities", - flask_query_set_element_type="activity", - flask_document_set_element_key="activity", - options=ConfigTestPatientSetOptions( - set_supports_deletion=True, - ), - ), - ConfigTestPatientSet( - name="activitylogs", - semantic_set_id=scope.database.patient.activity_logs.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_activity_log_factory", - document_factory_fixture_set="data_fake_activity_logs_factory", - database_get_set_function=scope.database.patient.activity_logs.get_activity_logs, - database_get_function=scope.database.patient.activity_logs.get_activity_log, - database_post_function=scope.database.patient.activity_logs.post_activity_log, - database_unsafe_update_function=None, - database_document_parameter_name="activity_log", - flask_query_set_type="activitylogs", - flask_document_set_key="activitylogs", - flask_query_set_element_type="activitylog", - flask_document_set_element_key="activitylog", - ), - ConfigTestPatientSet( - name="activityschedules", - semantic_set_id=scope.database.patient.activity_schedules.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_activity_schedule_factory", - document_factory_fixture_set="data_fake_activity_schedules_factory", - database_get_set_function=scope.database.patient.activity_schedules.get_activity_schedules, - database_get_function=scope.database.patient.activity_schedules.get_activity_schedule, - database_post_function=scope.database.patient.activity_schedules.post_activity_schedule, - database_unsafe_update_function=None, - database_document_parameter_name="activity_schedule", - flask_query_set_type="activityschedules", - flask_document_set_key="activityschedules", - flask_query_set_element_type="activityschedule", - flask_document_set_element_key="activityschedule", - options=ConfigTestPatientSetOptions( - set_supports_deletion=True, - ), - ), - ConfigTestPatientSet( - name="assessments", - semantic_set_id=scope.database.patient.assessments.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_assessment_factory", - document_factory_fixture_set="data_fake_assessments_factory", - database_get_set_function=scope.database.patient.assessments.get_assessments, - database_get_function=scope.database.patient.assessments.get_assessment, - database_post_function=None, # Assessments have fixed set IDs - database_unsafe_update_function=scope.database.patient_unsafe_utils.unsafe_update_assessment, - database_document_parameter_name="assessment", - flask_query_set_type="assessments", - flask_document_set_key="assessments", - flask_query_set_element_type="assessment", - flask_document_set_element_key="assessment", - options=ConfigTestPatientSetOptions( - set_id_will_already_exist=True, - set_element_will_already_exist=True, - ), - ), - ConfigTestPatientSet( - name="assessmentlogs", - semantic_set_id=scope.database.patient.assessment_logs.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_assessment_log_factory", - document_factory_fixture_set="data_fake_assessment_logs_factory", - database_get_set_function=scope.database.patient.assessment_logs.get_assessment_logs, - database_get_function=scope.database.patient.assessment_logs.get_assessment_log, - database_post_function=scope.database.patient.assessment_logs.post_assessment_log, - database_unsafe_update_function=None, - database_document_parameter_name="assessment_log", - flask_query_set_type="assessmentlogs", - flask_document_set_key="assessmentlogs", - flask_query_set_element_type="assessmentlog", - flask_document_set_element_key="assessmentlog", - ), - ConfigTestPatientSet( - name="casereviews", - semantic_set_id=scope.database.patient.case_reviews.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_case_review_factory", - document_factory_fixture_set="data_fake_case_reviews_factory", - database_get_set_function=scope.database.patient.case_reviews.get_case_reviews, - database_get_function=scope.database.patient.case_reviews.get_case_review, - database_post_function=scope.database.patient.case_reviews.post_case_review, - database_unsafe_update_function=None, - database_document_parameter_name="case_review", - flask_query_set_type="casereviews", - flask_document_set_key="casereviews", - flask_query_set_element_type="casereview", - flask_document_set_element_key="casereview", - ), - ConfigTestPatientSet( - name="moodlogs", - semantic_set_id=scope.database.patient.mood_logs.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_mood_log_factory", - document_factory_fixture_set="data_fake_mood_logs_factory", - database_get_set_function=scope.database.patient.mood_logs.get_mood_logs, - database_get_function=scope.database.patient.mood_logs.get_mood_log, - database_post_function=scope.database.patient.mood_logs.post_mood_log, - database_unsafe_update_function=None, - database_document_parameter_name="mood_log", - flask_query_set_type="moodlogs", - flask_document_set_key="moodlogs", - flask_query_set_element_type="moodlog", - flask_document_set_element_key="moodlog", - ), - ConfigTestPatientSet( - name="sessions", - semantic_set_id=scope.database.patient.sessions.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_session_factory", - document_factory_fixture_set="data_fake_sessions_factory", - database_get_set_function=scope.database.patient.sessions.get_sessions, - database_get_function=scope.database.patient.sessions.get_session, - database_post_function=scope.database.patient.sessions.post_session, - database_unsafe_update_function=None, - database_document_parameter_name="session", - flask_query_set_type="sessions", - flask_document_set_key="sessions", - flask_query_set_element_type="session", - flask_document_set_element_key="session", - ), - ConfigTestPatientSet( - name="scheduledactivities", - semantic_set_id=scope.database.patient.scheduled_activities.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_scheduled_activity_factory", - document_factory_fixture_set="data_fake_scheduled_activities_factory", - database_get_set_function=scope.database.patient.scheduled_activities.get_scheduled_activities, - database_get_function=scope.database.patient.scheduled_activities.get_scheduled_activity, - database_post_function=scope.database.patient.scheduled_activities.post_scheduled_activity, - database_unsafe_update_function=None, - database_document_parameter_name="scheduled_activity", - flask_query_set_type="scheduledactivities", - flask_document_set_key="scheduledactivities", - flask_query_set_element_type="scheduledactivity", - flask_document_set_element_key="scheduledactivity", - ), - ConfigTestPatientSet( - name="scheduledassessments", - semantic_set_id=scope.database.patient.scheduled_assessments.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_scheduled_assessment_factory", - document_factory_fixture_set="data_fake_scheduled_assessments_factory", - database_get_set_function=scope.database.patient.scheduled_assessments.get_scheduled_assessments, - database_get_function=scope.database.patient.scheduled_assessments.get_scheduled_assessment, - database_post_function=scope.database.patient.scheduled_assessments.post_scheduled_assessment, - database_unsafe_update_function=None, - database_document_parameter_name="scheduled_assessment", - flask_query_set_type="scheduledassessments", - flask_document_set_key="scheduledassessments", - flask_query_set_element_type="scheduledassessment", - flask_document_set_element_key="scheduledassessment", - options=ConfigTestPatientSetOptions( - set_id_will_already_exist=False, - set_element_will_already_exist=True, - ), - ), - ConfigTestPatientSet( - name="values", - semantic_set_id=scope.database.patient.values.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_value_factory", - document_factory_fixture_set="data_fake_values_factory", - database_get_set_function=scope.database.patient.values.get_values, - database_get_function=scope.database.patient.values.get_value, - database_post_function=scope.database.patient.values.post_value, - database_unsafe_update_function=None, - database_document_parameter_name="value", - flask_query_set_type="values", - flask_document_set_key="values", - flask_query_set_element_type="value", - flask_document_set_element_key="value", - options=ConfigTestPatientSetOptions( - set_supports_deletion=True, - ), + database_document_parameter_name="recent_entry_review", + flask_query_set_type="recententryreviews", + flask_document_set_key="recententryreviews", + flask_query_set_element_type="recententryreview", + flask_document_set_element_key="recententryreview", ), + # ConfigTestPatientSet( + # name="sessions", + # semantic_set_id=scope.database.patient.sessions.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_session_factory", + # document_factory_fixture_set="data_fake_sessions_factory", + # database_get_set_function=scope.database.patient.sessions.get_sessions, + # database_get_function=scope.database.patient.sessions.get_session, + # database_post_function=scope.database.patient.sessions.post_session, + # database_unsafe_update_function=None, + # database_document_parameter_name="session", + # flask_query_set_type="sessions", + # flask_document_set_key="sessions", + # flask_query_set_element_type="session", + # flask_document_set_element_key="session", + # ), + # ConfigTestPatientSet( + # name="scheduledactivities", + # semantic_set_id=scope.database.patient.scheduled_activities.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_scheduled_activity_factory", + # document_factory_fixture_set="data_fake_scheduled_activities_factory", + # database_get_set_function=scope.database.patient.scheduled_activities.get_scheduled_activities, + # database_get_function=scope.database.patient.scheduled_activities.get_scheduled_activity, + # database_post_function=scope.database.patient.scheduled_activities.post_scheduled_activity, + # database_unsafe_update_function=None, + # database_document_parameter_name="scheduled_activity", + # flask_query_set_type="scheduledactivities", + # flask_document_set_key="scheduledactivities", + # flask_query_set_element_type="scheduledactivity", + # flask_document_set_element_key="scheduledactivity", + # ), + # ConfigTestPatientSet( + # name="scheduledassessments", + # semantic_set_id=scope.database.patient.scheduled_assessments.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_scheduled_assessment_factory", + # document_factory_fixture_set="data_fake_scheduled_assessments_factory", + # database_get_set_function=scope.database.patient.scheduled_assessments.get_scheduled_assessments, + # database_get_function=scope.database.patient.scheduled_assessments.get_scheduled_assessment, + # database_post_function=scope.database.patient.scheduled_assessments.post_scheduled_assessment, + # database_unsafe_update_function=None, + # database_document_parameter_name="scheduled_assessment", + # flask_query_set_type="scheduledassessments", + # flask_document_set_key="scheduledassessments", + # flask_query_set_element_type="scheduledassessment", + # flask_document_set_element_key="scheduledassessment", + # options=ConfigTestPatientSetOptions( + # set_id_will_already_exist=False, + # set_element_will_already_exist=True, + # ), + # ), + # ConfigTestPatientSet( + # name="values", + # semantic_set_id=scope.database.patient.values.SEMANTIC_SET_ID, + # document_factory_fixture_set_element="data_fake_value_factory", + # document_factory_fixture_set="data_fake_values_factory", + # database_get_set_function=scope.database.patient.values.get_values, + # database_get_function=scope.database.patient.values.get_value, + # database_post_function=scope.database.patient.values.post_value, + # database_unsafe_update_function=None, + # database_document_parameter_name="value", + # flask_query_set_type="values", + # flask_document_set_key="values", + # flask_query_set_element_type="value", + # flask_document_set_element_key="value", + # options=ConfigTestPatientSetOptions( + # set_supports_deletion=True, + # ), + # ), ] QUERY_SET = "patient/{patient_id}/{query_type}" From ba12e7250d3722fd41ebc870d125f155d30cc566 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Mon, 5 Aug 2024 21:30:59 -0700 Subject: [PATCH 02/26] Add Mark Reviewed and Undo Previous Mark Functionality to Registry --- .../src/components/common/ContentsMenu.tsx | 125 ++++++++++----- web_registry/src/services/strings.ts | 2 + web_registry/src/stores/PatientStore.ts | 86 ++++++++-- web_shared/patientService.ts | 17 ++ web_shared/serviceTypes.ts | 9 ++ web_shared/sorting.ts | 147 ++++++++++-------- web_shared/types.ts | 9 ++ 7 files changed, 283 insertions(+), 112 deletions(-) diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index 6861dae88..e01923ba3 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -1,9 +1,10 @@ import React, { FunctionComponent } from "react"; -// import AssignmentTurnedInOutlinedIcon from "@mui/icons-material/AssignmentTurnedInOutlined"; +import AssignmentReturnOutlinedIcon from "@mui/icons-material/AssignmentReturnOutlined"; +import AssignmentTurnedInOutlinedIcon from "@mui/icons-material/AssignmentTurnedInOutlined"; import { Badge, - // Button, + Button, FormHelperText, List, ListItem, @@ -17,7 +18,10 @@ import withTheme from "@mui/styles/withTheme"; import { format } from "date-fns"; import throttle from "lodash.throttle"; import { action, observable } from "mobx"; -import { observer } from "mobx-react"; +import { observer, useLocalObservable } from "mobx-react"; +import { IRecentEntryReview } from "shared/types"; +import { getString } from "src/services/strings"; +import { usePatient, useStores } from "src/stores/stores"; import styled, { CSSObject, ThemedStyledProps } from "styled-components"; const TitleContainer = withTheme( @@ -122,8 +126,40 @@ export const ContentsMenu: FunctionComponent = observer( recentEntryCutoffDateTime, recentEntryBadgeContent, } = props; + const currentPatient = usePatient(); + const { authStore } = useStores(); const theme = useTheme(); + const markReviewState = useLocalObservable<{ + recentEntryReview: IRecentEntryReview; + }>(() => ({ + recentEntryReview: { + editedDateTime: new Date(), + effectiveDateTime: new Date(), + providerName: authStore.currentUserIdentity?.name, + } as IRecentEntryReview, + })); + + const onRecentEntryMarkReviewed = action(() => { + const { recentEntryReview } = markReviewState; + currentPatient.addRecentEntryReview({ + ...recentEntryReview, + editedDateTime: new Date(), + effectiveDateTime: new Date(), + }); + }); + + const onRecentEntryMarkUndo = action(() => { + const previousRecentEntryReview = + currentPatient.recentEntryReviewsSortedByDateAndTimeDescending[1]; + const { recentEntryReview } = markReviewState; + currentPatient.addRecentEntryReview({ + ...recentEntryReview, + editedDateTime: new Date(), + effectiveDateTime: previousRecentEntryReview.effectiveDateTime, + }); + }); + const itemsClientRef = React.useRef([]); React.useEffect(() => { itemsClientRef.current = contents.map((c) => { @@ -238,53 +274,66 @@ export const ContentsMenu: FunctionComponent = observer( ); }; - return ( -
- - - CONTENTS - {!!recentEntryCutoffDateTime && !!recentEntryBadgeContent && ( - - New Since: -
- {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} -
- )} -
-
- {contents.map(createListItem)} -
- ); - // return ( //
// - // - // - // CONTENTS + // + // CONTENTS + // {!!recentEntryCutoffDateTime && !!recentEntryBadgeContent && ( // - // Last Reviewed: + // New Since: //
// {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} //
- //
- // - // - // + // )} //
//
// {contents.map(createListItem)} //
// ); + + return ( +
+ + + + CONTENTS + + Last Reviewed: +
+ {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} +
+
+ + + + +
+
+ {contents.map(createListItem)} +
+ ); }, ); diff --git a/web_registry/src/services/strings.ts b/web_registry/src/services/strings.ts index e02042e5e..388105b7a 100644 --- a/web_registry/src/services/strings.ts +++ b/web_registry/src/services/strings.ts @@ -90,6 +90,8 @@ const _strings = { patient_behavioral_checklist_resources_header: "Relevant Forms and Worksheets", patient_behavioral_checklist_not_completed: "Not completed", + recent_patient_entry_mark_reviewed: "Mark Reviewed", + recent_patient_entry_undo_previous_mark: "Undo Previous Mark", }; type Strings = typeof _strings; diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index ad3b4a84a..0447db703 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -21,6 +21,7 @@ import { sortCaseReviewsOrSessionsByDate, SortDirection, sortMoodLogsByDateAndTime, + sortRecentEntryReviewsByDateAndTime, sortScheduledActivitiesByDateAndTime, sortSessionsByDate, sortValuesByDateAndTime, @@ -41,6 +42,7 @@ import { IMoodLog, IPatient, IPatientProfile, + IRecentEntryReview, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -63,18 +65,18 @@ export interface IPatientStore extends IPatient { readonly recentEntryCutoffDateTime: Date | undefined; readonly recentEntryActivities: IActivity[] | undefined; readonly recentEntryActivityLogsSortedByDateAndTimeDescending: - | IActivityLog[] - | undefined; + | IActivityLog[] + | undefined; readonly recentEntryAssessmentLogsSortedByDateAndTimeDescending: - | IAssessmentLog[] - | undefined; + | IAssessmentLog[] + | undefined; readonly recentEntryMoodLogsSortedByDateAndTimeDescending: - | IMoodLog[] - | undefined; + | IMoodLog[] + | undefined; readonly recentEntrySafetyPlan: ISafetyPlan | undefined; readonly recentEntryScheduledActivitiesSortedByDateAndTimeDescending: - | IScheduledActivity[] - | undefined; + | IScheduledActivity[] + | undefined; readonly recentEntryValues: IValue[] | undefined; // UI states @@ -89,6 +91,7 @@ export interface IPatientStore extends IPatient { readonly loadClinicalHistoryState: IPromiseQueryState; readonly loadMoodLogsState: IPromiseQueryState; readonly loadProfileState: IPromiseQueryState; + readonly loadRecentEntryReviewsState: IPromiseQueryState; readonly loadSafetyPlanState: IPromiseQueryState; readonly loadScheduledActivitiesState: IPromiseQueryState; readonly loadScheduledAssessmentsState: IPromiseQueryState; @@ -110,6 +113,7 @@ export interface IPatientStore extends IPatient { readonly sessionsSortedByDate: ISession[]; readonly moodLogsSortedByDateAndTime: IMoodLog[]; readonly moodLogsSortedByDateAndTimeDescending: IMoodLog[]; + readonly recentEntryReviewsSortedByDateAndTimeDescending: IRecentEntryReview[]; readonly scheduledActivitiesSortedByDateAndTimeDescending: IScheduledActivity[]; readonly valuesSortedByDateAndTimeDescending: IValue[]; @@ -165,6 +169,9 @@ export interface IPatientStore extends IPatient { // Patient profile updateProfile(profile: IPatientProfile): Promise; + // Recent entry review + addRecentEntryReview(review: IRecentEntryReview): Promise; + // Session addSession(session: ISession): void; updateSession(session: ISession): void; @@ -183,6 +190,7 @@ export class PatientStore implements IPatientStore { private readonly loadClinicalHistoryQuery: PromiseQuery; private readonly loadMoodLogsQuery: PromiseQuery; private readonly loadProfileQuery: PromiseQuery; + private readonly loadRecentEntryReviewsQuery: PromiseQuery; private readonly loadSafetyPlanQuery: PromiseQuery; private readonly loadSessionsQuery: PromiseQuery; private readonly loadScheduledActivitiesQuery: PromiseQuery< @@ -265,6 +273,10 @@ export class PatientStore implements IPatientStore { patient.profile, "loadProfile", ); + this.loadRecentEntryReviewsQuery = new PromiseQuery( + patient.recentEntryReviews, + "loadRecentEntryReviews", + ); this.loadSafetyPlanQuery = new PromiseQuery( patient.safetyPlan, "loadSafetyPlan", @@ -376,6 +388,14 @@ export class PatientStore implements IPatientStore { return sortMoodLogsByDateAndTime(this.moodLogs, SortDirection.DESCENDING); } + @computed get recentEntryReviews() { + return this.loadRecentEntryReviewsQuery.value || []; + } + + @computed get recentEntryReviewsSortedByDateAndTimeDescending() { + return sortRecentEntryReviewsByDateAndTime(this.recentEntryReviews, SortDirection.DESCENDING); + } + @computed get scheduledActivitiesSortedByDateAndTimeDescending() { return sortScheduledActivitiesByDateAndTime( this.scheduledActivities, @@ -456,7 +476,7 @@ export class PatientStore implements IPatientStore { this.recentEntryActivityLogsSortedByDateAndTimeDescending.length > 0) || (!!this.recentEntryAssessmentLogsSortedByDateAndTimeDescending && this.recentEntryAssessmentLogsSortedByDateAndTimeDescending.length > - 0) || + 0) || (!!this.recentEntryMoodLogsSortedByDateAndTimeDescending && this.recentEntryMoodLogsSortedByDateAndTimeDescending.length > 0) || !!this.recentEntrySafetyPlan || @@ -472,6 +492,15 @@ export class PatientStore implements IPatientStore { } @computed get recentEntryCutoffDateTime() { + // // Initially, stub the function to return now minus two weeks. + // // Eventually, this will be calculated based on when a social worker marks a patient as reviewed. + // let cutoffDateTime = new Date(); + // //cutoffDateTime = subDays(cutoffDateTime, 14); + // + // cutoffDateTime = this.recentEntryReviewsSortedByDateAndTimeDescending.length > 0 ? this.recentEntryReviewsSortedByDateAndTimeDescending[0].effectiveDateTime : subDays(cutoffDateTime, 14); + // + // return cutoffDateTime; + return this.profile.enrollmentDate; } @@ -708,6 +737,10 @@ export class PatientStore implements IPatientStore { return this.loadProfileQuery; } + @computed get loadRecentEntryReviewsState() { + return this.loadRecentEntryReviewsQuery; + } + @computed get loadSafetyPlanState() { return this.loadSafetyPlanQuery; } @@ -880,6 +913,7 @@ export class PatientStore implements IPatientStore { ); this.loadMoodLogsQuery.fromPromise(Promise.resolve(patient.moodLogs)); this.loadProfileQuery.fromPromise(Promise.resolve(patient.profile)); + this.loadRecentEntryReviewsQuery.fromPromise(Promise.resolve(patient.recentEntryReviews)); this.loadSafetyPlanQuery.fromPromise( Promise.resolve(patient.safetyPlan), ); @@ -1180,10 +1214,10 @@ export class PatientStore implements IPatientStore { ), primaryCareManager: patientProfile.primaryCareManager ? { - name: patientProfile.primaryCareManager?.name, - providerId: patientProfile.primaryCareManager?.providerId, - role: patientProfile.primaryCareManager?.role, - } + name: patientProfile.primaryCareManager?.name, + providerId: patientProfile.primaryCareManager?.providerId, + role: patientProfile.primaryCareManager?.role, + } : undefined, }); @@ -1193,6 +1227,23 @@ export class PatientStore implements IPatientStore { onSingletonConflict("profile"), ); } + + // Recent Entry Review + @action.bound + public async addRecentEntryReview(recentEntryReview: IRecentEntryReview) { + const promise = this.patientService + .addRecentEntryReview(toJS(recentEntryReview)) + .then((addedReview) => { + return this.recentEntryReviews.slice().concat([addedReview]); + }); + + await this.loadAndLogQuery( + () => promise, + this.loadRecentEntryReviewsQuery, + this.onRecentEntryReviewConflict + ); + } + // Session @action.bound public async addSession(session: ISession) { @@ -1275,6 +1326,15 @@ export class PatientStore implements IPatientStore { )(responseData); }; + private onRecentEntryReviewConflict = (responseData?: any) => { + return onArrayConflict( + "recententryreview", + "sesrecentEntryReviewIdsionId", + () => this.recentEntryReviews, + logger, + )(responseData); + }; + private onSessionConflict = (responseData?: any) => { return onArrayConflict( "session", diff --git a/web_shared/patientService.ts b/web_shared/patientService.ts index a2cbb2780..6f34f9f1f 100644 --- a/web_shared/patientService.ts +++ b/web_shared/patientService.ts @@ -28,6 +28,8 @@ import { IPatientProfileRequest, IPatientProfileResponse, IPatientResponse, + IRecentEntryReviewRequest, + IRecentEntryReviewResponse, ISafetyPlanRequest, ISafetyPlanResponse, IScheduledActivityListResponse, @@ -53,6 +55,7 @@ import { IPatient, IPatientConfig, IPatientProfile, + IRecentEntryReview, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -122,6 +125,8 @@ export interface IPatientService extends IServiceBase { getMoodLogs(): Promise; addMoodLog(moodLog: IMoodLog): Promise; + addRecentEntryReview(recentEntryReview: IRecentEntryReview): Promise; + getValues(): Promise; addValue(value: IValue): Promise; deleteValue(value: IValue): Promise; @@ -581,6 +586,18 @@ class PatientService extends ServiceBase implements IPatientService { return response.data?.moodlog; } + public async addRecentEntryReview(recentEntryReview: IRecentEntryReview): Promise { + (recentEntryReview as any)._type = "recentEntryReview"; + + const response = await this.axiosInstance.post( + `/recententryreviews`, + { + recententryreview: recentEntryReview, + } as IRecentEntryReviewRequest, + ); + return response.data?.recententryreview; + } + public async getValues(): Promise { const response = await this.axiosInstance.get(`/values`); diff --git a/web_shared/serviceTypes.ts b/web_shared/serviceTypes.ts index 90d625e94..1f130136c 100644 --- a/web_shared/serviceTypes.ts +++ b/web_shared/serviceTypes.ts @@ -11,6 +11,7 @@ import { IPatientIdentity, IPatientProfile, IProviderIdentity, + IRecentEntryReview, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -96,6 +97,14 @@ export interface IMoodLogRequest { moodlog: IMoodLog; } +export interface IRecentEntryReviewResponse extends IServiceResponse { + recententryreview: IRecentEntryReview; +} + +export interface IRecentEntryReviewRequest { + recententryreview: IRecentEntryReview; +} + export interface IActivityListResponse extends IServiceResponse { activities: IActivity[]; } diff --git a/web_shared/sorting.ts b/web_shared/sorting.ts index e2085fbe1..9665d4f27 100644 --- a/web_shared/sorting.ts +++ b/web_shared/sorting.ts @@ -7,6 +7,7 @@ import { IAssessmentLog, ICaseReview, IMoodLog, + IRecentEntryReview, IScheduledActivity, ISession, IValue, @@ -24,13 +25,13 @@ export const sortingDirectionComparator: ( comparator, sortingDirection, ) { - switch (sortingDirection) { - case SortDirection.ASCENDING: - return comparator; - case SortDirection.DESCENDING: - return (compareA, compareB) => comparator(compareB, compareA); - } -}; + switch (sortingDirection) { + case SortDirection.ASCENDING: + return comparator; + case SortDirection.DESCENDING: + return (compareA, compareB) => comparator(compareB, compareA); + } + }; export const compareActivityByName: ( compareA: IActivity, @@ -91,6 +92,13 @@ export const compareMoodLogsByDateAndTime: ( return compareAsc(compareA.recordedDateTime, compareB.recordedDateTime); }; +export const compareRecentEntryReviewsByDateAndTime: ( + compareA: IRecentEntryReview, + compareB: IRecentEntryReview, +) => number = function (compareA, compareB): number { + return compareAsc(compareA.editedDateTime, compareB.editedDateTime); +}; + export const compareScheduledActivitiesByDateAndTime: ( compareA: IScheduledActivity, compareB: IScheduledActivity, @@ -129,15 +137,15 @@ export const sortActivitiesByDateAndTime: ( activities, sortingDirection = SortDirection.ASCENDING, ) { - return activities - .slice() - .sort( - sortingDirectionComparator( - compareActivitiesByDateAndTime, - sortingDirection, - ), - ); -}; + return activities + .slice() + .sort( + sortingDirectionComparator( + compareActivitiesByDateAndTime, + sortingDirection, + ), + ); + }; export const sortActivitiesByName: (activities: IActivity[]) => IActivity[] = function (activities) { @@ -151,15 +159,15 @@ export const sortActivityLogsByDateAndTime: ( activityLogs, sortingDirection = SortDirection.ASCENDING, ) { - return activityLogs - .slice() - .sort( - sortingDirectionComparator( - compareActivityLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return activityLogs + .slice() + .sort( + sortingDirectionComparator( + compareActivityLogsByDateAndTime, + sortingDirection, + ), + ); + }; export const sortActivitySchedulesByDateAndTime: ( activitySchedules: IActivitySchedule[], @@ -174,15 +182,15 @@ export const sortAssessmentLogsByDateAndTime: ( assessmentLogs, sortingDirection = SortDirection.ASCENDING, ) { - return assessmentLogs - .slice() - .sort( - sortingDirectionComparator( - compareAssessmentLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return assessmentLogs + .slice() + .sort( + sortingDirectionComparator( + compareAssessmentLogsByDateAndTime, + sortingDirection, + ), + ); + }; export const sortCaseReviewsByDate: ( caseReviews: ICaseReview[], @@ -197,15 +205,15 @@ export const sortCaseReviewsOrSessionsByDate: ( caseReviewsOrSessions, sortingDirection = SortDirection.ASCENDING, ) { - return caseReviewsOrSessions - .slice() - .sort( - sortingDirectionComparator( - compareCaseReviewsOrSessionsByDate, - sortingDirection, - ), - ); -}; + return caseReviewsOrSessions + .slice() + .sort( + sortingDirectionComparator( + compareCaseReviewsOrSessionsByDate, + sortingDirection, + ), + ); + }; export const sortMoodLogsByDateAndTime: ( moodLogs: IMoodLog[], @@ -214,15 +222,32 @@ export const sortMoodLogsByDateAndTime: ( moodLogs, sortingDirection = SortDirection.ASCENDING, ) { - return moodLogs - .slice() - .sort( - sortingDirectionComparator( - compareMoodLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return moodLogs + .slice() + .sort( + sortingDirectionComparator( + compareMoodLogsByDateAndTime, + sortingDirection, + ), + ); + }; + +export const sortRecentEntryReviewsByDateAndTime: ( + recentEntryReviews: IRecentEntryReview[], + sortingDirection?: SortDirection, +) => IRecentEntryReview[] = function ( + recentEntryReviews, + sortingDirection = SortDirection.ASCENDING, +) { + return recentEntryReviews + .slice() + .sort( + sortingDirectionComparator( + compareRecentEntryReviewsByDateAndTime, + sortingDirection, + ), + ); + }; export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities: IScheduledActivity[], @@ -231,15 +256,15 @@ export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities, sortingDirection = SortDirection.ASCENDING, ) { - return scheduledActivities - .slice() - .sort( - sortingDirectionComparator( - compareScheduledActivitiesByDateAndTime, - sortingDirection, - ), - ); -}; + return scheduledActivities + .slice() + .sort( + sortingDirectionComparator( + compareScheduledActivitiesByDateAndTime, + sortingDirection, + ), + ); + }; export const sortSessionsByDate: (sessions: ISession[]) => ISession[] = function (sessions) { diff --git a/web_shared/types.ts b/web_shared/types.ts index ce311d8cf..0d25e550c 100644 --- a/web_shared/types.ts +++ b/web_shared/types.ts @@ -232,6 +232,12 @@ export interface IContact { emergencyNumber?: string; } +export interface IRecentEntryReview { + editedDateTime: Date; + effectiveDateTime: Date; + providerName?: string; +} + export interface ISafetyPlan { assigned: boolean; assignedDateTime?: Date; @@ -300,6 +306,9 @@ export interface IPatient { // Values values: IValue[]; + // Recent entry reviews + recentEntryReviews: IRecentEntryReview[]; + // Sessions sessions: ISession[]; caseReviews: ICaseReview[]; From b4d3a51250e67f7b5815ee224d479d628212e4b2 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 09:11:50 -0700 Subject: [PATCH 03/26] Invoke format --- .../test_schemas/test_fake_data_schemas.py | 12 +- server_flask/blueprints/registry/patients.py | 8 +- web_registry/src/stores/PatientStore.ts | 51 ++++--- web_shared/patientService.ts | 8 +- web_shared/sorting.ts | 140 +++++++++--------- 5 files changed, 119 insertions(+), 100 deletions(-) diff --git a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py index b4c843963..0fd6802a2 100644 --- a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py +++ b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py @@ -508,9 +508,9 @@ def test_fake_data_schema( == document_set_element["_set_id"] ) else: - document_set_element[config.expected_semantic_set_id] = ( - document_set_element["_set_id"] - ) + document_set_element[ + config.expected_semantic_set_id + ] = document_set_element["_set_id"] else: assert "_set_id" not in document_set_element document_set_element["_set_id"] = collection_utils.generate_set_id() @@ -519,9 +519,9 @@ def test_fake_data_schema( assert ( config.expected_semantic_set_id not in document_set_element ) - document_set_element[config.expected_semantic_set_id] = ( - document_set_element["_set_id"] - ) + document_set_element[ + config.expected_semantic_set_id + ] = document_set_element["_set_id"] document_set_element = document_utils.normalize_document( document=document_set_element diff --git a/server_flask/blueprints/registry/patients.py b/server_flask/blueprints/registry/patients.py index a67253dcc..f268ecc6b 100644 --- a/server_flask/blueprints/registry/patients.py +++ b/server_flask/blueprints/registry/patients.py @@ -123,10 +123,10 @@ def _construct_patient_document( # Scheduled Assessments # TODO: this access currently modifies documents, cannot be replaced - patient_document["scheduledAssessments"] = ( - scope.database.patient.scheduled_assessments.get_scheduled_assessments( - collection=patient_collection - ) + patient_document[ + "scheduledAssessments" + ] = scope.database.patient.scheduled_assessments.get_scheduled_assessments( + collection=patient_collection ) # Scheduled Activities diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 0447db703..1bf217905 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -65,18 +65,18 @@ export interface IPatientStore extends IPatient { readonly recentEntryCutoffDateTime: Date | undefined; readonly recentEntryActivities: IActivity[] | undefined; readonly recentEntryActivityLogsSortedByDateAndTimeDescending: - | IActivityLog[] - | undefined; + | IActivityLog[] + | undefined; readonly recentEntryAssessmentLogsSortedByDateAndTimeDescending: - | IAssessmentLog[] - | undefined; + | IAssessmentLog[] + | undefined; readonly recentEntryMoodLogsSortedByDateAndTimeDescending: - | IMoodLog[] - | undefined; + | IMoodLog[] + | undefined; readonly recentEntrySafetyPlan: ISafetyPlan | undefined; readonly recentEntryScheduledActivitiesSortedByDateAndTimeDescending: - | IScheduledActivity[] - | undefined; + | IScheduledActivity[] + | undefined; readonly recentEntryValues: IValue[] | undefined; // UI states @@ -190,7 +190,9 @@ export class PatientStore implements IPatientStore { private readonly loadClinicalHistoryQuery: PromiseQuery; private readonly loadMoodLogsQuery: PromiseQuery; private readonly loadProfileQuery: PromiseQuery; - private readonly loadRecentEntryReviewsQuery: PromiseQuery; + private readonly loadRecentEntryReviewsQuery: PromiseQuery< + IRecentEntryReview[] + >; private readonly loadSafetyPlanQuery: PromiseQuery; private readonly loadSessionsQuery: PromiseQuery; private readonly loadScheduledActivitiesQuery: PromiseQuery< @@ -393,7 +395,10 @@ export class PatientStore implements IPatientStore { } @computed get recentEntryReviewsSortedByDateAndTimeDescending() { - return sortRecentEntryReviewsByDateAndTime(this.recentEntryReviews, SortDirection.DESCENDING); + return sortRecentEntryReviewsByDateAndTime( + this.recentEntryReviews, + SortDirection.DESCENDING, + ); } @computed get scheduledActivitiesSortedByDateAndTimeDescending() { @@ -476,7 +481,7 @@ export class PatientStore implements IPatientStore { this.recentEntryActivityLogsSortedByDateAndTimeDescending.length > 0) || (!!this.recentEntryAssessmentLogsSortedByDateAndTimeDescending && this.recentEntryAssessmentLogsSortedByDateAndTimeDescending.length > - 0) || + 0) || (!!this.recentEntryMoodLogsSortedByDateAndTimeDescending && this.recentEntryMoodLogsSortedByDateAndTimeDescending.length > 0) || !!this.recentEntrySafetyPlan || @@ -501,7 +506,15 @@ export class PatientStore implements IPatientStore { // // return cutoffDateTime; - return this.profile.enrollmentDate; + // return this.profile.enrollmentDate; + + cutoffDateTime = + this.recentEntryReviewsSortedByDateAndTimeDescending.length > 0 + ? this.recentEntryReviewsSortedByDateAndTimeDescending[0] + .effectiveDateTime + : subDays(cutoffDateTime, 14); + + return cutoffDateTime; } @computed get recentEntryActivities() { @@ -913,7 +926,9 @@ export class PatientStore implements IPatientStore { ); this.loadMoodLogsQuery.fromPromise(Promise.resolve(patient.moodLogs)); this.loadProfileQuery.fromPromise(Promise.resolve(patient.profile)); - this.loadRecentEntryReviewsQuery.fromPromise(Promise.resolve(patient.recentEntryReviews)); + this.loadRecentEntryReviewsQuery.fromPromise( + Promise.resolve(patient.recentEntryReviews), + ); this.loadSafetyPlanQuery.fromPromise( Promise.resolve(patient.safetyPlan), ); @@ -1214,10 +1229,10 @@ export class PatientStore implements IPatientStore { ), primaryCareManager: patientProfile.primaryCareManager ? { - name: patientProfile.primaryCareManager?.name, - providerId: patientProfile.primaryCareManager?.providerId, - role: patientProfile.primaryCareManager?.role, - } + name: patientProfile.primaryCareManager?.name, + providerId: patientProfile.primaryCareManager?.providerId, + role: patientProfile.primaryCareManager?.role, + } : undefined, }); @@ -1240,7 +1255,7 @@ export class PatientStore implements IPatientStore { await this.loadAndLogQuery( () => promise, this.loadRecentEntryReviewsQuery, - this.onRecentEntryReviewConflict + this.onRecentEntryReviewConflict, ); } diff --git a/web_shared/patientService.ts b/web_shared/patientService.ts index 6f34f9f1f..00aed951e 100644 --- a/web_shared/patientService.ts +++ b/web_shared/patientService.ts @@ -125,7 +125,9 @@ export interface IPatientService extends IServiceBase { getMoodLogs(): Promise; addMoodLog(moodLog: IMoodLog): Promise; - addRecentEntryReview(recentEntryReview: IRecentEntryReview): Promise; + addRecentEntryReview( + recentEntryReview: IRecentEntryReview, + ): Promise; getValues(): Promise; addValue(value: IValue): Promise; @@ -586,7 +588,9 @@ class PatientService extends ServiceBase implements IPatientService { return response.data?.moodlog; } - public async addRecentEntryReview(recentEntryReview: IRecentEntryReview): Promise { + public async addRecentEntryReview( + recentEntryReview: IRecentEntryReview, + ): Promise { (recentEntryReview as any)._type = "recentEntryReview"; const response = await this.axiosInstance.post( diff --git a/web_shared/sorting.ts b/web_shared/sorting.ts index 9665d4f27..c52822dbb 100644 --- a/web_shared/sorting.ts +++ b/web_shared/sorting.ts @@ -25,13 +25,13 @@ export const sortingDirectionComparator: ( comparator, sortingDirection, ) { - switch (sortingDirection) { - case SortDirection.ASCENDING: - return comparator; - case SortDirection.DESCENDING: - return (compareA, compareB) => comparator(compareB, compareA); - } - }; + switch (sortingDirection) { + case SortDirection.ASCENDING: + return comparator; + case SortDirection.DESCENDING: + return (compareA, compareB) => comparator(compareB, compareA); + } +}; export const compareActivityByName: ( compareA: IActivity, @@ -137,15 +137,15 @@ export const sortActivitiesByDateAndTime: ( activities, sortingDirection = SortDirection.ASCENDING, ) { - return activities - .slice() - .sort( - sortingDirectionComparator( - compareActivitiesByDateAndTime, - sortingDirection, - ), - ); - }; + return activities + .slice() + .sort( + sortingDirectionComparator( + compareActivitiesByDateAndTime, + sortingDirection, + ), + ); +}; export const sortActivitiesByName: (activities: IActivity[]) => IActivity[] = function (activities) { @@ -159,15 +159,15 @@ export const sortActivityLogsByDateAndTime: ( activityLogs, sortingDirection = SortDirection.ASCENDING, ) { - return activityLogs - .slice() - .sort( - sortingDirectionComparator( - compareActivityLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return activityLogs + .slice() + .sort( + sortingDirectionComparator( + compareActivityLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortActivitySchedulesByDateAndTime: ( activitySchedules: IActivitySchedule[], @@ -182,15 +182,15 @@ export const sortAssessmentLogsByDateAndTime: ( assessmentLogs, sortingDirection = SortDirection.ASCENDING, ) { - return assessmentLogs - .slice() - .sort( - sortingDirectionComparator( - compareAssessmentLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return assessmentLogs + .slice() + .sort( + sortingDirectionComparator( + compareAssessmentLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortCaseReviewsByDate: ( caseReviews: ICaseReview[], @@ -205,15 +205,15 @@ export const sortCaseReviewsOrSessionsByDate: ( caseReviewsOrSessions, sortingDirection = SortDirection.ASCENDING, ) { - return caseReviewsOrSessions - .slice() - .sort( - sortingDirectionComparator( - compareCaseReviewsOrSessionsByDate, - sortingDirection, - ), - ); - }; + return caseReviewsOrSessions + .slice() + .sort( + sortingDirectionComparator( + compareCaseReviewsOrSessionsByDate, + sortingDirection, + ), + ); +}; export const sortMoodLogsByDateAndTime: ( moodLogs: IMoodLog[], @@ -222,15 +222,15 @@ export const sortMoodLogsByDateAndTime: ( moodLogs, sortingDirection = SortDirection.ASCENDING, ) { - return moodLogs - .slice() - .sort( - sortingDirectionComparator( - compareMoodLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return moodLogs + .slice() + .sort( + sortingDirectionComparator( + compareMoodLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortRecentEntryReviewsByDateAndTime: ( recentEntryReviews: IRecentEntryReview[], @@ -239,15 +239,15 @@ export const sortRecentEntryReviewsByDateAndTime: ( recentEntryReviews, sortingDirection = SortDirection.ASCENDING, ) { - return recentEntryReviews - .slice() - .sort( - sortingDirectionComparator( - compareRecentEntryReviewsByDateAndTime, - sortingDirection, - ), - ); - }; + return recentEntryReviews + .slice() + .sort( + sortingDirectionComparator( + compareRecentEntryReviewsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities: IScheduledActivity[], @@ -256,15 +256,15 @@ export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities, sortingDirection = SortDirection.ASCENDING, ) { - return scheduledActivities - .slice() - .sort( - sortingDirectionComparator( - compareScheduledActivitiesByDateAndTime, - sortingDirection, - ), - ); - }; + return scheduledActivities + .slice() + .sort( + sortingDirectionComparator( + compareScheduledActivitiesByDateAndTime, + sortingDirection, + ), + ); +}; export const sortSessionsByDate: (sessions: ISession[]) => ISession[] = function (sessions) { From d7d37ba320b070d4261df971f601b1397744b2bf Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 16:35:13 -0700 Subject: [PATCH 04/26] Store providerId instead of providerName --- scope_shared/scope/schemas/documents/recent-entry-review.json | 4 ++-- .../testing/fake_data/fixtures_fake_recent_entry_review.py | 2 +- web_registry/src/components/common/ContentsMenu.tsx | 2 +- web_shared/types.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scope_shared/scope/schemas/documents/recent-entry-review.json b/scope_shared/scope/schemas/documents/recent-entry-review.json index 9b6c20e5a..6d04e2d48 100644 --- a/scope_shared/scope/schemas/documents/recent-entry-review.json +++ b/scope_shared/scope/schemas/documents/recent-entry-review.json @@ -26,10 +26,10 @@ "effectiveDateTime": { "$ref": "/schemas/utils/datetime#/properties/datetime" }, - "providerName": { + "providerId": { "type": "string" } }, "additionalProperties": false, - "required": ["_type", "editedDateTime", "effectiveDateTime", "providerName"] + "required": ["_type", "editedDateTime", "effectiveDateTime", "providerId"] } diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py index afb7a72d7..542b3d2fd 100644 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py @@ -42,7 +42,7 @@ def factory() -> dict: ) ) ), - "providerName": faker_factory.name(), + "providerId": faker_factory.name(), } return fake_recent_entry_review diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index e01923ba3..d5526f62d 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -136,7 +136,7 @@ export const ContentsMenu: FunctionComponent = observer( recentEntryReview: { editedDateTime: new Date(), effectiveDateTime: new Date(), - providerName: authStore.currentUserIdentity?.name, + providerId: authStore.currentUserIdentity?.providerId, } as IRecentEntryReview, })); diff --git a/web_shared/types.ts b/web_shared/types.ts index 0d25e550c..d172425e5 100644 --- a/web_shared/types.ts +++ b/web_shared/types.ts @@ -235,7 +235,7 @@ export interface IContact { export interface IRecentEntryReview { editedDateTime: Date; effectiveDateTime: Date; - providerName?: string; + providerId?: string; } export interface ISafetyPlan { From 7fbef979415748159a2ed3ad8dae8270505009a0 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 17:18:27 -0700 Subject: [PATCH 05/26] Change to --- ...ecent_entry_reviews.py => review_marks.py} | 28 ++-- scope_shared/scope/schema.py | 8 +- scope_shared/scope/schemas/document.json | 2 +- .../documents/recent-entry-reviews.json | 9 - ...ent-entry-review.json => review-mark.json} | 10 +- .../scope/schemas/documents/review-marks.json | 9 + scope_shared/scope/testing/__init__.py | 4 +- .../fixtures_fake_recent_entry_reviews.py | 51 ------ ...review.py => fixtures_fake_review_mark.py} | 20 +-- .../fake_data/fixtures_fake_review_marks.py | 51 ++++++ .../test_schemas/test_fake_data_schemas.py | 32 ++-- server_flask/app.py | 4 +- server_flask/blueprints/registry/patients.py | 16 +- ...ecent_entry_reviews.py => review_marks.py} | 80 +++++---- .../test_flask/registry/test_patient_set.py | 26 +-- .../src/components/common/ContentsMenu.tsx | 28 ++-- web_registry/src/stores/PatientStore.ts | 90 +++++----- web_shared/patientService.ts | 30 ++-- web_shared/serviceTypes.ts | 10 +- web_shared/sorting.ts | 156 +++++++++--------- web_shared/types.ts | 4 +- 21 files changed, 333 insertions(+), 335 deletions(-) rename scope_shared/scope/database/patient/{recent_entry_reviews.py => review_marks.py} (71%) delete mode 100644 scope_shared/scope/schemas/documents/recent-entry-reviews.json rename scope_shared/scope/schemas/documents/{recent-entry-review.json => review-mark.json} (75%) create mode 100644 scope_shared/scope/schemas/documents/review-marks.json delete mode 100644 scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py rename scope_shared/scope/testing/fake_data/{fixtures_fake_recent_entry_review.py => fixtures_fake_review_mark.py} (75%) create mode 100644 scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py rename server_flask/blueprints/registry/{recent_entry_reviews.py => review_marks.py} (55%) diff --git a/scope_shared/scope/database/patient/recent_entry_reviews.py b/scope_shared/scope/database/patient/review_marks.py similarity index 71% rename from scope_shared/scope/database/patient/recent_entry_reviews.py rename to scope_shared/scope/database/patient/review_marks.py index b5a453c82..6c046d00d 100644 --- a/scope_shared/scope/database/patient/recent_entry_reviews.py +++ b/scope_shared/scope/database/patient/review_marks.py @@ -3,16 +3,16 @@ import pymongo.collection import scope.database.collection_utils -DOCUMENT_TYPE = "recentEntryReview" -SEMANTIC_SET_ID = "recentEntryReviewId" +DOCUMENT_TYPE = "reviewMark" +SEMANTIC_SET_ID = "reviewMarkId" -def get_recent_entry_reviews( +def get_review_marks( *, collection: pymongo.collection.Collection, ) -> Optional[List[dict]]: """ - Get list of "recentEntryReview" documents. + Get list of "reviewMark" documents. """ return scope.database.collection_utils.get_set( @@ -21,13 +21,13 @@ def get_recent_entry_reviews( ) -def get_recent_entry_review( +def get_review_mark( *, collection: pymongo.collection.Collection, set_id: str, ) -> Optional[dict]: """ - Get "recentEntryReview" document. + Get "reviewMark" document. """ return scope.database.collection_utils.get_set_element( @@ -37,31 +37,31 @@ def get_recent_entry_review( ) -def post_recent_entry_review( +def post_review_mark( *, collection: pymongo.collection.Collection, - recent_entry_review: dict, + review_mark: dict, ) -> scope.database.collection_utils.SetPostResult: """ - Post "recentEntryReview" document. + Post "reviewMark" document. """ return scope.database.collection_utils.post_set_element( collection=collection, document_type=DOCUMENT_TYPE, semantic_set_id=SEMANTIC_SET_ID, - document=recent_entry_review, + document=review_mark, ) -def put_recent_entry_review( +def put_review_mark( *, collection: pymongo.collection.Collection, - recent_entry_review: dict, + review_mark: dict, set_id: str, ) -> scope.database.collection_utils.SetPutResult: """ - Put "recentEntryReview" document. + Put "reviewMark" document. """ return scope.database.collection_utils.put_set_element( @@ -69,5 +69,5 @@ def put_recent_entry_review( document_type=DOCUMENT_TYPE, semantic_set_id=SEMANTIC_SET_ID, set_id=set_id, - document=recent_entry_review, + document=review_mark, ) diff --git a/scope_shared/scope/schema.py b/scope_shared/scope/schema.py index dfc973eb9..f49d06f13 100644 --- a/scope_shared/scope/schema.py +++ b/scope_shared/scope/schema.py @@ -42,8 +42,8 @@ provider_identities_schema: Optional[jschon.JSONSchema] = None referral_status_schema: Optional[jschon.JSONSchema] = None regexes: Optional[jschon.JSONSchema] = None -recent_entry_review_schema: Optional[jschon.JSONSchema] = None -recent_entry_reviews_schema: Optional[jschon.JSONSchema] = None +review_mark_schema: Optional[jschon.JSONSchema] = None +review_marks_schema: Optional[jschon.JSONSchema] = None resource_content_schema: Optional[jschon.JSONSchema] = None resource_contents_schema: Optional[jschon.JSONSchema] = None safety_plan_schema: Optional[jschon.JSONSchema] = None @@ -102,8 +102,8 @@ "patient_profile_schema": "documents/patient-profile.json", "provider_identity_schema": "documents/provider-identity.json", "provider_identities_schema": "documents/provider-identities.json", - "recent_entry_review_schema": "documents/recent-entry-review.json", - "recent_entry_reviews_schema": "documents/recent-entry-reviews.json", + "review_mark_schema": "documents/review-mark.json", + "review_marks_schema": "documents/review-marks.json", "safety_plan_schema": "documents/safety-plan.json", "scheduled_activity_schema": "documents/scheduled-activity.json", "scheduled_activities_schema": "documents/scheduled-activities.json", diff --git a/scope_shared/scope/schemas/document.json b/scope_shared/scope/schemas/document.json index 4357ca015..b4588995d 100644 --- a/scope_shared/scope/schemas/document.json +++ b/scope_shared/scope/schemas/document.json @@ -37,7 +37,7 @@ "$ref": "/schemas/documents/patient-profile" }, { - "$ref": "/schemas/documents/recent-entry-review" + "$ref": "/schemas/documents/review-mark" }, { "$ref": "/schemas/documents/safety-plan" diff --git a/scope_shared/scope/schemas/documents/recent-entry-reviews.json b/scope_shared/scope/schemas/documents/recent-entry-reviews.json deleted file mode 100644 index 2df4b4c27..000000000 --- a/scope_shared/scope/schemas/documents/recent-entry-reviews.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://uwscope.org/schemas/documents/recent-entry-reviews", - "title": "IRecentEntryReview[]", - "type": "array", - "items": { - "$ref": "/schemas/documents/recent-entry-review" - } -} diff --git a/scope_shared/scope/schemas/documents/recent-entry-review.json b/scope_shared/scope/schemas/documents/review-mark.json similarity index 75% rename from scope_shared/scope/schemas/documents/recent-entry-review.json rename to scope_shared/scope/schemas/documents/review-mark.json index 6d04e2d48..ffde8eeae 100644 --- a/scope_shared/scope/schemas/documents/recent-entry-review.json +++ b/scope_shared/scope/schemas/documents/review-mark.json @@ -1,15 +1,15 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://uwscope.org/schemas/documents/recent-entry-review", - "title": "IRecentEntryReview", - "description": "IRecentEntryReview Type", + "$id": "https://uwscope.org/schemas/documents/review-mark", + "title": "IReviewMark", + "description": "IReviewMark Type", "type": "object", "properties": { "_id": { "type": "string" }, "_type": { - "const": "recentEntryReview" + "const": "reviewMark" }, "_set_id": { "type": "string" @@ -17,7 +17,7 @@ "_rev": { "type": "number" }, - "recentEntryReviewId": { + "reviewMarkId": { "type": "string" }, "editedDateTime": { diff --git a/scope_shared/scope/schemas/documents/review-marks.json b/scope_shared/scope/schemas/documents/review-marks.json new file mode 100644 index 000000000..0a04db8b6 --- /dev/null +++ b/scope_shared/scope/schemas/documents/review-marks.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://uwscope.org/schemas/documents/review-marks", + "title": "IReviewMark[]", + "type": "array", + "items": { + "$ref": "/schemas/documents/review-mark" + } +} diff --git a/scope_shared/scope/testing/__init__.py b/scope_shared/scope/testing/__init__.py index d06b42e49..4cd5667b0 100644 --- a/scope_shared/scope/testing/__init__.py +++ b/scope_shared/scope/testing/__init__.py @@ -20,8 +20,8 @@ "scope.testing.fake_data.fixtures_fake_patient_profile", "scope.testing.fake_data.fixtures_fake_provider_identity", "scope.testing.fake_data.fixtures_fake_referral_status", - "scope.testing.fake_data.fixtures_fake_recent_entry_review", - "scope.testing.fake_data.fixtures_fake_recent_entry_reviews", + "scope.testing.fake_data.fixtures_fake_review_mark", + "scope.testing.fake_data.fixtures_fake_review_marks", "scope.testing.fake_data.fixtures_fake_safety_plan", "scope.testing.fake_data.fixtures_fake_session", "scope.testing.fake_data.fixtures_fake_sessions", diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py b/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py deleted file mode 100644 index 45e51bc7b..000000000 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_reviews.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest -import random -from typing import Callable, List - -import scope.database.document_utils as document_utils -import scope.schema -import scope.schema_utils -import scope.testing.fake_data.fake_utils as fake_utils - - -def fake_recent_entry_reviews_factory( - *, - fake_recent_entry_review_factory: Callable[[], dict], -) -> Callable[[], List[dict]]: - """ - Obtain a factory that will generate a list of fake recent entry review documents. - """ - - def factory() -> List[dict]: - fake_recent_entry_reviews = [ - fake_recent_entry_review_factory() for _ in range(random.randint(1, 5)) - ] - - return fake_recent_entry_reviews - - return factory - - -@pytest.fixture(name="data_fake_recent_entry_reviews_factory") -def fixture_data_fake_recent_entry_reviews_factory( - data_fake_recent_entry_review_factory: Callable[[], dict], -) -> Callable[[], List[dict]]: - """ - Fixture for data_fake_recent_entry_reviews_factory. - """ - - unvalidated_factory = fake_recent_entry_reviews_factory( - fake_recent_entry_review_factory=data_fake_recent_entry_review_factory, - ) - - def factory() -> List[dict]: - fake_recent_entry_reviews = unvalidated_factory() - - scope.schema_utils.xfail_for_invalid_schema( - schema=scope.schema.recent_entry_reviews_schema, - data=fake_recent_entry_reviews, - ) - - return fake_recent_entry_reviews - - return factory diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py similarity index 75% rename from scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py rename to scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py index 542b3d2fd..43c90c477 100644 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_recent_entry_review.py +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py @@ -6,14 +6,14 @@ from typing import Callable import scope.database.date_utils as date_utils -import scope.database.patient.recent_entry_reviews +import scope.database.patient.review_marks import scope.enums import scope.schema import scope.schema_utils import scope.testing.fake_data.fake_utils as fake_utils -def fake_recent_entry_review_factory( +def fake_review_mark_factory( *, faker_factory: faker.Faker, ) -> Callable[[], dict]: @@ -22,8 +22,8 @@ def fake_recent_entry_review_factory( """ def factory() -> dict: - fake_recent_entry_review = { - "_type": scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE, + fake_review_mark = { + "_type": scope.database.patient.review_marks.DOCUMENT_TYPE, "editedDateTime": date_utils.format_datetime( pytz.utc.localize( faker_factory.date_time_between_dates( @@ -45,20 +45,20 @@ def factory() -> dict: "providerId": faker_factory.name(), } - return fake_recent_entry_review + return fake_review_mark return factory -@pytest.fixture(name="data_fake_recent_entry_review_factory") -def fixture_data_fake_recent_entry_review_factory( +@pytest.fixture(name="data_fake_review_mark_factory") +def fixture_data_fake_review_mark_factory( faker: faker.Faker, ) -> Callable[[], dict]: """ - Fixture for data_fake_recent_entry_review_factory. + Fixture for data_fake_review_mark_factory. """ - unvalidated_factory = fake_recent_entry_review_factory( + unvalidated_factory = fake_review_mark_factory( faker_factory=faker, ) @@ -66,7 +66,7 @@ def factory() -> dict: fake_recent_entry = unvalidated_factory() scope.schema_utils.xfail_for_invalid_schema( - schema=scope.schema.recent_entry_review_schema, + schema=scope.schema.review_mark_schema, data=fake_recent_entry, ) diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py b/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py new file mode 100644 index 000000000..a27ee8939 --- /dev/null +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py @@ -0,0 +1,51 @@ +import pytest +import random +from typing import Callable, List + +import scope.database.document_utils as document_utils +import scope.schema +import scope.schema_utils +import scope.testing.fake_data.fake_utils as fake_utils + + +def fake_review_marks_factory( + *, + fake_review_mark_factory: Callable[[], dict], +) -> Callable[[], List[dict]]: + """ + Obtain a factory that will generate a list of fake recent entry review documents. + """ + + def factory() -> List[dict]: + fake_review_marks = [ + fake_review_mark_factory() for _ in range(random.randint(1, 5)) + ] + + return fake_review_marks + + return factory + + +@pytest.fixture(name="data_fake_review_marks_factory") +def fixture_data_fake_review_marks_factory( + data_fake_review_mark_factory: Callable[[], dict], +) -> Callable[[], List[dict]]: + """ + Fixture for data_fake_review_marks_factory. + """ + + unvalidated_factory = fake_review_marks_factory( + fake_review_mark_factory=data_fake_review_mark_factory, + ) + + def factory() -> List[dict]: + fake_review_marks = unvalidated_factory() + + scope.schema_utils.xfail_for_invalid_schema( + schema=scope.schema.review_marks_schema, + data=fake_review_marks, + ) + + return fake_review_marks + + return factory diff --git a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py index 0fd6802a2..2c369d283 100644 --- a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py +++ b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py @@ -13,7 +13,7 @@ import scope.database.patient.assessments import scope.database.patient.case_reviews import scope.database.patient.mood_logs -import scope.database.patient.recent_entry_reviews +import scope.database.patient.review_marks import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments import scope.database.patient.sessions @@ -38,8 +38,8 @@ import scope.testing.fake_data.fixtures_fake_mood_logs import scope.testing.fake_data.fixtures_fake_patient_profile import scope.testing.fake_data.fixtures_fake_provider_identity -import scope.testing.fake_data.fixtures_fake_recent_entry_review -import scope.testing.fake_data.fixtures_fake_recent_entry_reviews +import scope.testing.fake_data.fixtures_fake_review_mark +import scope.testing.fake_data.fixtures_fake_review_marks import scope.testing.fake_data.fixtures_fake_referral_status import scope.testing.fake_data.fixtures_fake_safety_plan import scope.testing.fake_data.fixtures_fake_session @@ -273,19 +273,19 @@ class ConfigTestFakeDataSchema: expected_set_ids=None, ), ConfigTestFakeDataSchema( - name="recent-entry-review", - schema=scope.schema.recent_entry_review_schema, - data_factory_fixture="data_fake_recent_entry_review_factory", + name="review-mark", + schema=scope.schema.review_mark_schema, + data_factory_fixture="data_fake_review_mark_factory", expected_document=True, expected_singleton=False, expected_set_element=True, - expected_semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + expected_semantic_set_id=scope.database.patient.review_marks.SEMANTIC_SET_ID, expected_set_ids=None, ), ConfigTestFakeDataSchema( - name="recent-entry-reviews", - schema=scope.schema.recent_entry_reviews_schema, - data_factory_fixture="data_fake_recent_entry_reviews_factory", + name="review-marks", + schema=scope.schema.review_marks_schema, + data_factory_fixture="data_fake_review_marks_factory", expected_document=False, expected_singleton=False, expected_set_element=False, @@ -508,9 +508,9 @@ def test_fake_data_schema( == document_set_element["_set_id"] ) else: - document_set_element[ - config.expected_semantic_set_id - ] = document_set_element["_set_id"] + document_set_element[config.expected_semantic_set_id] = ( + document_set_element["_set_id"] + ) else: assert "_set_id" not in document_set_element document_set_element["_set_id"] = collection_utils.generate_set_id() @@ -519,9 +519,9 @@ def test_fake_data_schema( assert ( config.expected_semantic_set_id not in document_set_element ) - document_set_element[ - config.expected_semantic_set_id - ] = document_set_element["_set_id"] + document_set_element[config.expected_semantic_set_id] = ( + document_set_element["_set_id"] + ) document_set_element = document_utils.normalize_document( document=document_set_element diff --git a/server_flask/app.py b/server_flask/app.py index f369e520c..e64138298 100644 --- a/server_flask/app.py +++ b/server_flask/app.py @@ -19,7 +19,7 @@ import blueprints.registry.patient_profile import blueprints.registry.patients import blueprints.registry.providers -import blueprints.registry.recent_entry_reviews +import blueprints.registry.review_marks import blueprints.registry.safety_plan import blueprints.registry.sessions import blueprints.registry.scheduled_activities @@ -151,7 +151,7 @@ def status(): url_prefix="/patient/", ) app.register_blueprint( - blueprints.registry.recent_entry_reviews.recent_entry_reviews_blueprint, + blueprints.registry.review_marks.review_marks_blueprint, url_prefix="/patient/", ) diff --git a/server_flask/blueprints/registry/patients.py b/server_flask/blueprints/registry/patients.py index f268ecc6b..95883277c 100644 --- a/server_flask/blueprints/registry/patients.py +++ b/server_flask/blueprints/registry/patients.py @@ -15,7 +15,7 @@ import scope.database.patient.clinical_history import scope.database.patient.mood_logs import scope.database.patient.patient_profile -import scope.database.patient.recent_entry_reviews +import scope.database.patient.review_marks import scope.database.patient.safety_plan import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments @@ -59,7 +59,7 @@ def _construct_patient_document( scope.database.patient.assessment_logs.DOCUMENT_TYPE, scope.database.patient.case_reviews.DOCUMENT_TYPE, scope.database.patient.mood_logs.DOCUMENT_TYPE, - scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE, + scope.database.patient.review_marks.DOCUMENT_TYPE, scope.database.patient.scheduled_activities.DOCUMENT_TYPE, scope.database.patient.sessions.DOCUMENT_TYPE, scope.database.patient.values.DOCUMENT_TYPE, @@ -112,8 +112,8 @@ def _construct_patient_document( ] # Recent Entry Reviews - patient_document["recentEntryReviews"] = documents_by_type[ - scope.database.patient.recent_entry_reviews.DOCUMENT_TYPE + patient_document["reviewMarks"] = documents_by_type[ + scope.database.patient.review_marks.DOCUMENT_TYPE ] # Safety Plan @@ -123,10 +123,10 @@ def _construct_patient_document( # Scheduled Assessments # TODO: this access currently modifies documents, cannot be replaced - patient_document[ - "scheduledAssessments" - ] = scope.database.patient.scheduled_assessments.get_scheduled_assessments( - collection=patient_collection + patient_document["scheduledAssessments"] = ( + scope.database.patient.scheduled_assessments.get_scheduled_assessments( + collection=patient_collection + ) ) # Scheduled Activities diff --git a/server_flask/blueprints/registry/recent_entry_reviews.py b/server_flask/blueprints/registry/review_marks.py similarity index 55% rename from server_flask/blueprints/registry/recent_entry_reviews.py rename to server_flask/blueprints/registry/review_marks.py index 83063db8c..3aa300a60 100644 --- a/server_flask/blueprints/registry/recent_entry_reviews.py +++ b/server_flask/blueprints/registry/review_marks.py @@ -5,25 +5,25 @@ import request_context import request_utils import scope.database -import scope.database.patient.recent_entry_reviews +import scope.database.patient.review_marks import scope.schema -recent_entry_reviews_blueprint = flask.Blueprint( - "recent_entry_reviews_blueprint", +review_marks_blueprint = flask.Blueprint( + "review_marks_blueprint", __name__, ) -@recent_entry_reviews_blueprint.route( - "//recententryreviews", +@review_marks_blueprint.route( + "//reviewmarks", methods=["GET"], ) @flask_json.as_json -def get_recent_entry_reviews(patient_id): +def get_review_marks(patient_id): context = request_context.authorized_for_patient(patient_id=patient_id) patient_collection = context.patient_collection(patient_id=patient_id) - documents = scope.database.patient.recent_entry_reviews.get_recent_entry_reviews( + documents = scope.database.patient.review_marks.get_review_marks( collection=patient_collection, ) @@ -33,36 +33,36 @@ def get_recent_entry_reviews(patient_id): ) return { - "recententryreviews": documents, + "reviewmarks": documents, } -@recent_entry_reviews_blueprint.route( - "//recententryreviews", +@review_marks_blueprint.route( + "//reviewmarks", methods=["POST"], ) @request_utils.validate_schema( - schema=scope.schema.recent_entry_review_schema, - key="recententryreview", + schema=scope.schema.review_mark_schema, + key="reviewmark", ) @flask_json.as_json -def post_recent_entry_reviews(patient_id): +def post_review_marks(patient_id): context = request_context.authorized_for_patient(patient_id=patient_id) patient_collection = context.patient_collection(patient_id=patient_id) # Obtain the document being put - document = flask.request.json["recententryreview"] + document = flask.request.json["reviewmark"] # Validate and normalize the request document = request_utils.set_post_request_validate( - semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + semantic_set_id=scope.database.patient.review_marks.SEMANTIC_SET_ID, document=document, ) # Store the document - result = scope.database.patient.recent_entry_reviews.post_recent_entry_review( + result = scope.database.patient.review_marks.post_review_mark( collection=patient_collection, - recent_entry_review=document, + review_mark=document, ) # Validate and normalize the response @@ -71,23 +71,23 @@ def post_recent_entry_reviews(patient_id): ) return { - "recententryreview": document_response, + "reviewmark": document_response, } -@recent_entry_reviews_blueprint.route( - "//recententryreview/", +@review_marks_blueprint.route( + "//reviewmark/", methods=["GET"], ) @flask_json.as_json -def get_recent_entry_review(patient_id, recententryreview_id): +def get_review_mark(patient_id, reviewmark_id): context = request_context.authorized_for_patient(patient_id=patient_id) patient_collection = context.patient_collection(patient_id=patient_id) # Get the document - document = scope.database.patient.recent_entry_reviews.get_recent_entry_review( + document = scope.database.patient.review_marks.get_review_mark( collection=patient_collection, - set_id=recententryreview_id, + set_id=reviewmark_id, ) # Validate and normalize the response @@ -96,46 +96,44 @@ def get_recent_entry_review(patient_id, recententryreview_id): ) return { - "recententryreview": document, + "reviewmark": document, } -@recent_entry_reviews_blueprint.route( - "//recententryreview/", +@review_marks_blueprint.route( + "//reviewmark/", methods=["PUT"], ) @request_utils.validate_schema( - schema=scope.schema.recent_entry_review_schema, - key="recententryreview", + schema=scope.schema.review_mark_schema, + key="reviewmark", ) @flask_json.as_json -def put_recent_entry_review(patient_id, recententryreview_id): +def put_review_mark(patient_id, reviewmark_id): context = request_context.authorized_for_patient(patient_id=patient_id) patient_collection = context.patient_collection(patient_id=patient_id) # Obtain the document being put - document = flask.request.json["recententryreview"] + document = flask.request.json["reviewmark"] # Validate and normalize the request document = request_utils.set_element_put_request_validate( - semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, + semantic_set_id=scope.database.patient.review_marks.SEMANTIC_SET_ID, document=document, - set_id=recententryreview_id, + set_id=reviewmark_id, ) # Store the document try: - result = scope.database.patient.recent_entry_reviews.put_recent_entry_review( + result = scope.database.patient.review_marks.put_review_mark( collection=patient_collection, - recent_entry_review=document, - set_id=recententryreview_id, + review_mark=document, + set_id=reviewmark_id, ) except pymongo.errors.DuplicateKeyError: # Indicates a revision race condition, return error with current revision - document_conflict = ( - scope.database.patient.recent_entry_reviews.get_recent_entry_review( - collection=patient_collection, set_id=recententryreview_id - ) + document_conflict = scope.database.patient.review_marks.get_review_mark( + collection=patient_collection, set_id=reviewmark_id ) # Validate and normalize the response document_conflict = request_utils.singleton_put_response_validate( @@ -144,7 +142,7 @@ def put_recent_entry_review(patient_id, recententryreview_id): request_utils.abort_revision_conflict( document={ - "recententryreview": document_conflict, + "reviewmark": document_conflict, } ) else: @@ -154,5 +152,5 @@ def put_recent_entry_review(patient_id, recententryreview_id): ) return { - "recententryreview": document_response, + "reviewmark": document_response, } diff --git a/server_flask/tests/test_flask/registry/test_patient_set.py b/server_flask/tests/test_flask/registry/test_patient_set.py index c765623a2..ef9138dfb 100644 --- a/server_flask/tests/test_flask/registry/test_patient_set.py +++ b/server_flask/tests/test_flask/registry/test_patient_set.py @@ -16,7 +16,7 @@ import scope.database.patient.assessment_logs import scope.database.patient.case_reviews import scope.database.patient.mood_logs -import scope.database.patient.recent_entry_reviews +import scope.database.patient.review_marks import scope.database.patient.sessions import scope.database.patient.scheduled_activities import scope.database.patient.scheduled_assessments @@ -193,19 +193,19 @@ class ConfigTestPatientSet: # flask_document_set_element_key="moodlog", # ), ConfigTestPatientSet( - name="recententryreviews", - semantic_set_id=scope.database.patient.recent_entry_reviews.SEMANTIC_SET_ID, - document_factory_fixture_set_element="data_fake_recent_entry_review_factory", - document_factory_fixture_set="data_fake_recent_entry_reviews_factory", - database_get_set_function=scope.database.patient.recent_entry_reviews.get_recent_entry_reviews, - database_get_function=scope.database.patient.recent_entry_reviews.get_recent_entry_review, - database_post_function=scope.database.patient.recent_entry_reviews.post_recent_entry_review, + name="reviewmarks", + semantic_set_id=scope.database.patient.review_marks.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_review_mark_factory", + document_factory_fixture_set="data_fake_review_marks_factory", + database_get_set_function=scope.database.patient.review_marks.get_review_marks, + database_get_function=scope.database.patient.review_marks.get_review_mark, + database_post_function=scope.database.patient.review_marks.post_review_mark, database_unsafe_update_function=None, - database_document_parameter_name="recent_entry_review", - flask_query_set_type="recententryreviews", - flask_document_set_key="recententryreviews", - flask_query_set_element_type="recententryreview", - flask_document_set_element_key="recententryreview", + database_document_parameter_name="review_mark", + flask_query_set_type="reviewmarks", + flask_document_set_key="reviewmarks", + flask_query_set_element_type="reviewmark", + flask_document_set_element_key="reviewmark", ), # ConfigTestPatientSet( # name="sessions", diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index d5526f62d..23c8da82a 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -19,7 +19,7 @@ import { format } from "date-fns"; import throttle from "lodash.throttle"; import { action, observable } from "mobx"; import { observer, useLocalObservable } from "mobx-react"; -import { IRecentEntryReview } from "shared/types"; +import { IReviewMark } from "shared/types"; import { getString } from "src/services/strings"; import { usePatient, useStores } from "src/stores/stores"; import styled, { CSSObject, ThemedStyledProps } from "styled-components"; @@ -131,32 +131,32 @@ export const ContentsMenu: FunctionComponent = observer( const theme = useTheme(); const markReviewState = useLocalObservable<{ - recentEntryReview: IRecentEntryReview; + reviewMark: IReviewMark; }>(() => ({ - recentEntryReview: { + reviewMark: { editedDateTime: new Date(), effectiveDateTime: new Date(), providerId: authStore.currentUserIdentity?.providerId, - } as IRecentEntryReview, + } as IReviewMark, })); const onRecentEntryMarkReviewed = action(() => { - const { recentEntryReview } = markReviewState; - currentPatient.addRecentEntryReview({ - ...recentEntryReview, + const { reviewMark } = markReviewState; + currentPatient.addReviewMark({ + ...reviewMark, editedDateTime: new Date(), effectiveDateTime: new Date(), }); }); const onRecentEntryMarkUndo = action(() => { - const previousRecentEntryReview = - currentPatient.recentEntryReviewsSortedByDateAndTimeDescending[1]; - const { recentEntryReview } = markReviewState; - currentPatient.addRecentEntryReview({ - ...recentEntryReview, + const previousReviewMark = + currentPatient.reviewMarksSortedByDateAndTimeDescending[1]; + const { reviewMark } = markReviewState; + currentPatient.addReviewMark({ + ...reviewMark, editedDateTime: new Date(), - effectiveDateTime: previousRecentEntryReview.effectiveDateTime, + effectiveDateTime: previousReviewMark.effectiveDateTime, }); }); @@ -320,7 +320,7 @@ export const ContentsMenu: FunctionComponent = observer( size="small" color="primary" disabled={ - currentPatient.recentEntryReviewsSortedByDateAndTimeDescending + currentPatient.reviewMarksSortedByDateAndTimeDescending .length <= 1 } startIcon={} diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 1bf217905..923dfed53 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -21,7 +21,7 @@ import { sortCaseReviewsOrSessionsByDate, SortDirection, sortMoodLogsByDateAndTime, - sortRecentEntryReviewsByDateAndTime, + sortReviewMarksByDateAndTime, sortScheduledActivitiesByDateAndTime, sortSessionsByDate, sortValuesByDateAndTime, @@ -42,7 +42,7 @@ import { IMoodLog, IPatient, IPatientProfile, - IRecentEntryReview, + IReviewMark, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -65,18 +65,18 @@ export interface IPatientStore extends IPatient { readonly recentEntryCutoffDateTime: Date | undefined; readonly recentEntryActivities: IActivity[] | undefined; readonly recentEntryActivityLogsSortedByDateAndTimeDescending: - | IActivityLog[] - | undefined; + | IActivityLog[] + | undefined; readonly recentEntryAssessmentLogsSortedByDateAndTimeDescending: - | IAssessmentLog[] - | undefined; + | IAssessmentLog[] + | undefined; readonly recentEntryMoodLogsSortedByDateAndTimeDescending: - | IMoodLog[] - | undefined; + | IMoodLog[] + | undefined; readonly recentEntrySafetyPlan: ISafetyPlan | undefined; readonly recentEntryScheduledActivitiesSortedByDateAndTimeDescending: - | IScheduledActivity[] - | undefined; + | IScheduledActivity[] + | undefined; readonly recentEntryValues: IValue[] | undefined; // UI states @@ -91,7 +91,7 @@ export interface IPatientStore extends IPatient { readonly loadClinicalHistoryState: IPromiseQueryState; readonly loadMoodLogsState: IPromiseQueryState; readonly loadProfileState: IPromiseQueryState; - readonly loadRecentEntryReviewsState: IPromiseQueryState; + readonly loadReviewMarksState: IPromiseQueryState; readonly loadSafetyPlanState: IPromiseQueryState; readonly loadScheduledActivitiesState: IPromiseQueryState; readonly loadScheduledAssessmentsState: IPromiseQueryState; @@ -113,7 +113,7 @@ export interface IPatientStore extends IPatient { readonly sessionsSortedByDate: ISession[]; readonly moodLogsSortedByDateAndTime: IMoodLog[]; readonly moodLogsSortedByDateAndTimeDescending: IMoodLog[]; - readonly recentEntryReviewsSortedByDateAndTimeDescending: IRecentEntryReview[]; + readonly reviewMarksSortedByDateAndTimeDescending: IReviewMark[]; readonly scheduledActivitiesSortedByDateAndTimeDescending: IScheduledActivity[]; readonly valuesSortedByDateAndTimeDescending: IValue[]; @@ -170,7 +170,7 @@ export interface IPatientStore extends IPatient { updateProfile(profile: IPatientProfile): Promise; // Recent entry review - addRecentEntryReview(review: IRecentEntryReview): Promise; + addReviewMark(review: IReviewMark): Promise; // Session addSession(session: ISession): void; @@ -190,8 +190,8 @@ export class PatientStore implements IPatientStore { private readonly loadClinicalHistoryQuery: PromiseQuery; private readonly loadMoodLogsQuery: PromiseQuery; private readonly loadProfileQuery: PromiseQuery; - private readonly loadRecentEntryReviewsQuery: PromiseQuery< - IRecentEntryReview[] + private readonly loadReviewMarksQuery: PromiseQuery< + IReviewMark[] >; private readonly loadSafetyPlanQuery: PromiseQuery; private readonly loadSessionsQuery: PromiseQuery; @@ -275,9 +275,9 @@ export class PatientStore implements IPatientStore { patient.profile, "loadProfile", ); - this.loadRecentEntryReviewsQuery = new PromiseQuery( - patient.recentEntryReviews, - "loadRecentEntryReviews", + this.loadReviewMarksQuery = new PromiseQuery( + patient.reviewMarks, + "loadReviewMarks", ); this.loadSafetyPlanQuery = new PromiseQuery( patient.safetyPlan, @@ -390,13 +390,13 @@ export class PatientStore implements IPatientStore { return sortMoodLogsByDateAndTime(this.moodLogs, SortDirection.DESCENDING); } - @computed get recentEntryReviews() { - return this.loadRecentEntryReviewsQuery.value || []; + @computed get reviewMarks() { + return this.loadReviewMarksQuery.value || []; } - @computed get recentEntryReviewsSortedByDateAndTimeDescending() { - return sortRecentEntryReviewsByDateAndTime( - this.recentEntryReviews, + @computed get reviewMarksSortedByDateAndTimeDescending() { + return sortReviewMarksByDateAndTime( + this.reviewMarks, SortDirection.DESCENDING, ); } @@ -481,7 +481,7 @@ export class PatientStore implements IPatientStore { this.recentEntryActivityLogsSortedByDateAndTimeDescending.length > 0) || (!!this.recentEntryAssessmentLogsSortedByDateAndTimeDescending && this.recentEntryAssessmentLogsSortedByDateAndTimeDescending.length > - 0) || + 0) || (!!this.recentEntryMoodLogsSortedByDateAndTimeDescending && this.recentEntryMoodLogsSortedByDateAndTimeDescending.length > 0) || !!this.recentEntrySafetyPlan || @@ -509,9 +509,9 @@ export class PatientStore implements IPatientStore { // return this.profile.enrollmentDate; cutoffDateTime = - this.recentEntryReviewsSortedByDateAndTimeDescending.length > 0 - ? this.recentEntryReviewsSortedByDateAndTimeDescending[0] - .effectiveDateTime + this.reviewMarksSortedByDateAndTimeDescending.length > 0 + ? this.reviewMarksSortedByDateAndTimeDescending[0] + .effectiveDateTime : subDays(cutoffDateTime, 14); return cutoffDateTime; @@ -750,8 +750,8 @@ export class PatientStore implements IPatientStore { return this.loadProfileQuery; } - @computed get loadRecentEntryReviewsState() { - return this.loadRecentEntryReviewsQuery; + @computed get loadReviewMarksState() { + return this.loadReviewMarksQuery; } @computed get loadSafetyPlanState() { @@ -926,8 +926,8 @@ export class PatientStore implements IPatientStore { ); this.loadMoodLogsQuery.fromPromise(Promise.resolve(patient.moodLogs)); this.loadProfileQuery.fromPromise(Promise.resolve(patient.profile)); - this.loadRecentEntryReviewsQuery.fromPromise( - Promise.resolve(patient.recentEntryReviews), + this.loadReviewMarksQuery.fromPromise( + Promise.resolve(patient.reviewMarks), ); this.loadSafetyPlanQuery.fromPromise( Promise.resolve(patient.safetyPlan), @@ -1229,10 +1229,10 @@ export class PatientStore implements IPatientStore { ), primaryCareManager: patientProfile.primaryCareManager ? { - name: patientProfile.primaryCareManager?.name, - providerId: patientProfile.primaryCareManager?.providerId, - role: patientProfile.primaryCareManager?.role, - } + name: patientProfile.primaryCareManager?.name, + providerId: patientProfile.primaryCareManager?.providerId, + role: patientProfile.primaryCareManager?.role, + } : undefined, }); @@ -1245,17 +1245,17 @@ export class PatientStore implements IPatientStore { // Recent Entry Review @action.bound - public async addRecentEntryReview(recentEntryReview: IRecentEntryReview) { + public async addReviewMark(reviewMark: IReviewMark) { const promise = this.patientService - .addRecentEntryReview(toJS(recentEntryReview)) + .addReviewMark(toJS(reviewMark)) .then((addedReview) => { - return this.recentEntryReviews.slice().concat([addedReview]); + return this.reviewMarks.slice().concat([addedReview]); }); - await this.loadAndLogQuery( + await this.loadAndLogQuery( () => promise, - this.loadRecentEntryReviewsQuery, - this.onRecentEntryReviewConflict, + this.loadReviewMarksQuery, + this.onReviewMarkConflict, ); } @@ -1341,11 +1341,11 @@ export class PatientStore implements IPatientStore { )(responseData); }; - private onRecentEntryReviewConflict = (responseData?: any) => { + private onReviewMarkConflict = (responseData?: any) => { return onArrayConflict( - "recententryreview", - "sesrecentEntryReviewIdsionId", - () => this.recentEntryReviews, + "reviewmark", + "reviewMarkId", + () => this.reviewMarks, logger, )(responseData); }; diff --git a/web_shared/patientService.ts b/web_shared/patientService.ts index 00aed951e..9c1680c21 100644 --- a/web_shared/patientService.ts +++ b/web_shared/patientService.ts @@ -28,8 +28,8 @@ import { IPatientProfileRequest, IPatientProfileResponse, IPatientResponse, - IRecentEntryReviewRequest, - IRecentEntryReviewResponse, + IReviewMarkRequest, + IReviewMarkResponse, ISafetyPlanRequest, ISafetyPlanResponse, IScheduledActivityListResponse, @@ -55,7 +55,7 @@ import { IPatient, IPatientConfig, IPatientProfile, - IRecentEntryReview, + IReviewMark, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -125,9 +125,9 @@ export interface IPatientService extends IServiceBase { getMoodLogs(): Promise; addMoodLog(moodLog: IMoodLog): Promise; - addRecentEntryReview( - recentEntryReview: IRecentEntryReview, - ): Promise; + addReviewMark( + reviewMark: IReviewMark, + ): Promise; getValues(): Promise; addValue(value: IValue): Promise; @@ -588,18 +588,18 @@ class PatientService extends ServiceBase implements IPatientService { return response.data?.moodlog; } - public async addRecentEntryReview( - recentEntryReview: IRecentEntryReview, - ): Promise { - (recentEntryReview as any)._type = "recentEntryReview"; + public async addReviewMark( + reviewMark: IReviewMark, + ): Promise { + (reviewMark as any)._type = "reviewMark"; - const response = await this.axiosInstance.post( - `/recententryreviews`, + const response = await this.axiosInstance.post( + `/reviewmarks`, { - recententryreview: recentEntryReview, - } as IRecentEntryReviewRequest, + reviewmark: reviewMark, + } as IReviewMarkRequest, ); - return response.data?.recententryreview; + return response.data?.reviewmark; } public async getValues(): Promise { diff --git a/web_shared/serviceTypes.ts b/web_shared/serviceTypes.ts index 1f130136c..d996e627d 100644 --- a/web_shared/serviceTypes.ts +++ b/web_shared/serviceTypes.ts @@ -11,7 +11,7 @@ import { IPatientIdentity, IPatientProfile, IProviderIdentity, - IRecentEntryReview, + IReviewMark, ISafetyPlan, IScheduledActivity, IScheduledAssessment, @@ -97,12 +97,12 @@ export interface IMoodLogRequest { moodlog: IMoodLog; } -export interface IRecentEntryReviewResponse extends IServiceResponse { - recententryreview: IRecentEntryReview; +export interface IReviewMarkResponse extends IServiceResponse { + reviewmark: IReviewMark; } -export interface IRecentEntryReviewRequest { - recententryreview: IRecentEntryReview; +export interface IReviewMarkRequest { + reviewmark: IReviewMark; } export interface IActivityListResponse extends IServiceResponse { diff --git a/web_shared/sorting.ts b/web_shared/sorting.ts index c52822dbb..3bdb6a462 100644 --- a/web_shared/sorting.ts +++ b/web_shared/sorting.ts @@ -7,7 +7,7 @@ import { IAssessmentLog, ICaseReview, IMoodLog, - IRecentEntryReview, + IReviewMark, IScheduledActivity, ISession, IValue, @@ -25,13 +25,13 @@ export const sortingDirectionComparator: ( comparator, sortingDirection, ) { - switch (sortingDirection) { - case SortDirection.ASCENDING: - return comparator; - case SortDirection.DESCENDING: - return (compareA, compareB) => comparator(compareB, compareA); - } -}; + switch (sortingDirection) { + case SortDirection.ASCENDING: + return comparator; + case SortDirection.DESCENDING: + return (compareA, compareB) => comparator(compareB, compareA); + } + }; export const compareActivityByName: ( compareA: IActivity, @@ -92,9 +92,9 @@ export const compareMoodLogsByDateAndTime: ( return compareAsc(compareA.recordedDateTime, compareB.recordedDateTime); }; -export const compareRecentEntryReviewsByDateAndTime: ( - compareA: IRecentEntryReview, - compareB: IRecentEntryReview, +export const compareReviewMarksByDateAndTime: ( + compareA: IReviewMark, + compareB: IReviewMark, ) => number = function (compareA, compareB): number { return compareAsc(compareA.editedDateTime, compareB.editedDateTime); }; @@ -137,15 +137,15 @@ export const sortActivitiesByDateAndTime: ( activities, sortingDirection = SortDirection.ASCENDING, ) { - return activities - .slice() - .sort( - sortingDirectionComparator( - compareActivitiesByDateAndTime, - sortingDirection, - ), - ); -}; + return activities + .slice() + .sort( + sortingDirectionComparator( + compareActivitiesByDateAndTime, + sortingDirection, + ), + ); + }; export const sortActivitiesByName: (activities: IActivity[]) => IActivity[] = function (activities) { @@ -159,15 +159,15 @@ export const sortActivityLogsByDateAndTime: ( activityLogs, sortingDirection = SortDirection.ASCENDING, ) { - return activityLogs - .slice() - .sort( - sortingDirectionComparator( - compareActivityLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return activityLogs + .slice() + .sort( + sortingDirectionComparator( + compareActivityLogsByDateAndTime, + sortingDirection, + ), + ); + }; export const sortActivitySchedulesByDateAndTime: ( activitySchedules: IActivitySchedule[], @@ -182,15 +182,15 @@ export const sortAssessmentLogsByDateAndTime: ( assessmentLogs, sortingDirection = SortDirection.ASCENDING, ) { - return assessmentLogs - .slice() - .sort( - sortingDirectionComparator( - compareAssessmentLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return assessmentLogs + .slice() + .sort( + sortingDirectionComparator( + compareAssessmentLogsByDateAndTime, + sortingDirection, + ), + ); + }; export const sortCaseReviewsByDate: ( caseReviews: ICaseReview[], @@ -205,15 +205,15 @@ export const sortCaseReviewsOrSessionsByDate: ( caseReviewsOrSessions, sortingDirection = SortDirection.ASCENDING, ) { - return caseReviewsOrSessions - .slice() - .sort( - sortingDirectionComparator( - compareCaseReviewsOrSessionsByDate, - sortingDirection, - ), - ); -}; + return caseReviewsOrSessions + .slice() + .sort( + sortingDirectionComparator( + compareCaseReviewsOrSessionsByDate, + sortingDirection, + ), + ); + }; export const sortMoodLogsByDateAndTime: ( moodLogs: IMoodLog[], @@ -222,32 +222,32 @@ export const sortMoodLogsByDateAndTime: ( moodLogs, sortingDirection = SortDirection.ASCENDING, ) { - return moodLogs - .slice() - .sort( - sortingDirectionComparator( - compareMoodLogsByDateAndTime, - sortingDirection, - ), - ); -}; + return moodLogs + .slice() + .sort( + sortingDirectionComparator( + compareMoodLogsByDateAndTime, + sortingDirection, + ), + ); + }; -export const sortRecentEntryReviewsByDateAndTime: ( - recentEntryReviews: IRecentEntryReview[], +export const sortReviewMarksByDateAndTime: ( + reviewMarks: IReviewMark[], sortingDirection?: SortDirection, -) => IRecentEntryReview[] = function ( - recentEntryReviews, +) => IReviewMark[] = function ( + reviewMarks, sortingDirection = SortDirection.ASCENDING, ) { - return recentEntryReviews - .slice() - .sort( - sortingDirectionComparator( - compareRecentEntryReviewsByDateAndTime, - sortingDirection, - ), - ); -}; + return reviewMarks + .slice() + .sort( + sortingDirectionComparator( + compareReviewMarksByDateAndTime, + sortingDirection, + ), + ); + }; export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities: IScheduledActivity[], @@ -256,15 +256,15 @@ export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities, sortingDirection = SortDirection.ASCENDING, ) { - return scheduledActivities - .slice() - .sort( - sortingDirectionComparator( - compareScheduledActivitiesByDateAndTime, - sortingDirection, - ), - ); -}; + return scheduledActivities + .slice() + .sort( + sortingDirectionComparator( + compareScheduledActivitiesByDateAndTime, + sortingDirection, + ), + ); + }; export const sortSessionsByDate: (sessions: ISession[]) => ISession[] = function (sessions) { diff --git a/web_shared/types.ts b/web_shared/types.ts index d172425e5..44da54ebc 100644 --- a/web_shared/types.ts +++ b/web_shared/types.ts @@ -232,7 +232,7 @@ export interface IContact { emergencyNumber?: string; } -export interface IRecentEntryReview { +export interface IReviewMark { editedDateTime: Date; effectiveDateTime: Date; providerId?: string; @@ -307,7 +307,7 @@ export interface IPatient { values: IValue[]; // Recent entry reviews - recentEntryReviews: IRecentEntryReview[]; + reviewMarks: IReviewMark[]; // Sessions sessions: ISession[]; From 0eb6f21e338a40548f12d9807e9fd1a2c2cd0323 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 17:20:41 -0700 Subject: [PATCH 06/26] Change recent entry to review mark --- .../scope/testing/fake_data/fixtures_fake_review_mark.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py index 43c90c477..110a84684 100644 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py @@ -63,13 +63,13 @@ def fixture_data_fake_review_mark_factory( ) def factory() -> dict: - fake_recent_entry = unvalidated_factory() + fake_review_mark = unvalidated_factory() scope.schema_utils.xfail_for_invalid_schema( schema=scope.schema.review_mark_schema, - data=fake_recent_entry, + data=fake_review_mark, ) - return fake_recent_entry + return fake_review_mark return factory From 1093df72e0eef9fc48d678744e0ddbfb57b3f863 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 17:40:41 -0700 Subject: [PATCH 07/26] invoke format and uncomment test config --- .../test_schemas/test_fake_data_schemas.py | 12 +- server_flask/blueprints/registry/patients.py | 8 +- .../test_flask/registry/test_patient_set.py | 364 +++++++++--------- web_registry/src/stores/PatientStore.ts | 33 +- web_shared/patientService.ts | 8 +- web_shared/sorting.ts | 140 +++---- 6 files changed, 279 insertions(+), 286 deletions(-) diff --git a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py index 2c369d283..d47ebd599 100644 --- a/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py +++ b/scope_shared/scope/testing/test_schemas/test_fake_data_schemas.py @@ -508,9 +508,9 @@ def test_fake_data_schema( == document_set_element["_set_id"] ) else: - document_set_element[config.expected_semantic_set_id] = ( - document_set_element["_set_id"] - ) + document_set_element[ + config.expected_semantic_set_id + ] = document_set_element["_set_id"] else: assert "_set_id" not in document_set_element document_set_element["_set_id"] = collection_utils.generate_set_id() @@ -519,9 +519,9 @@ def test_fake_data_schema( assert ( config.expected_semantic_set_id not in document_set_element ) - document_set_element[config.expected_semantic_set_id] = ( - document_set_element["_set_id"] - ) + document_set_element[ + config.expected_semantic_set_id + ] = document_set_element["_set_id"] document_set_element = document_utils.normalize_document( document=document_set_element diff --git a/server_flask/blueprints/registry/patients.py b/server_flask/blueprints/registry/patients.py index 95883277c..a8794cf94 100644 --- a/server_flask/blueprints/registry/patients.py +++ b/server_flask/blueprints/registry/patients.py @@ -123,10 +123,10 @@ def _construct_patient_document( # Scheduled Assessments # TODO: this access currently modifies documents, cannot be replaced - patient_document["scheduledAssessments"] = ( - scope.database.patient.scheduled_assessments.get_scheduled_assessments( - collection=patient_collection - ) + patient_document[ + "scheduledAssessments" + ] = scope.database.patient.scheduled_assessments.get_scheduled_assessments( + collection=patient_collection ) # Scheduled Activities diff --git a/server_flask/tests/test_flask/registry/test_patient_set.py b/server_flask/tests/test_flask/registry/test_patient_set.py index ef9138dfb..444e4acc0 100644 --- a/server_flask/tests/test_flask/registry/test_patient_set.py +++ b/server_flask/tests/test_flask/registry/test_patient_set.py @@ -77,121 +77,121 @@ class ConfigTestPatientSet: TEST_CONFIGS = [ - # ConfigTestPatientSet( - # name="activities", - # semantic_set_id=scope.database.patient.activities.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_activity_factory", - # document_factory_fixture_set="data_fake_activities_factory", - # database_get_set_function=scope.database.patient.activities.get_activities, - # database_get_function=scope.database.patient.activities.get_activity, - # database_post_function=scope.database.patient.activities.post_activity, - # database_unsafe_update_function=None, - # database_document_parameter_name="activity", - # flask_query_set_type="activities", - # flask_document_set_key="activities", - # flask_query_set_element_type="activity", - # flask_document_set_element_key="activity", - # options=ConfigTestPatientSetOptions( - # set_supports_deletion=True, - # ), - # ), - # ConfigTestPatientSet( - # name="activitylogs", - # semantic_set_id=scope.database.patient.activity_logs.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_activity_log_factory", - # document_factory_fixture_set="data_fake_activity_logs_factory", - # database_get_set_function=scope.database.patient.activity_logs.get_activity_logs, - # database_get_function=scope.database.patient.activity_logs.get_activity_log, - # database_post_function=scope.database.patient.activity_logs.post_activity_log, - # database_unsafe_update_function=None, - # database_document_parameter_name="activity_log", - # flask_query_set_type="activitylogs", - # flask_document_set_key="activitylogs", - # flask_query_set_element_type="activitylog", - # flask_document_set_element_key="activitylog", - # ), - # ConfigTestPatientSet( - # name="activityschedules", - # semantic_set_id=scope.database.patient.activity_schedules.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_activity_schedule_factory", - # document_factory_fixture_set="data_fake_activity_schedules_factory", - # database_get_set_function=scope.database.patient.activity_schedules.get_activity_schedules, - # database_get_function=scope.database.patient.activity_schedules.get_activity_schedule, - # database_post_function=scope.database.patient.activity_schedules.post_activity_schedule, - # database_unsafe_update_function=None, - # database_document_parameter_name="activity_schedule", - # flask_query_set_type="activityschedules", - # flask_document_set_key="activityschedules", - # flask_query_set_element_type="activityschedule", - # flask_document_set_element_key="activityschedule", - # options=ConfigTestPatientSetOptions( - # set_supports_deletion=True, - # ), - # ), - # ConfigTestPatientSet( - # name="assessments", - # semantic_set_id=scope.database.patient.assessments.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_assessment_factory", - # document_factory_fixture_set="data_fake_assessments_factory", - # database_get_set_function=scope.database.patient.assessments.get_assessments, - # database_get_function=scope.database.patient.assessments.get_assessment, - # database_post_function=None, # Assessments have fixed set IDs - # database_unsafe_update_function=scope.database.patient_unsafe_utils.unsafe_update_assessment, - # database_document_parameter_name="assessment", - # flask_query_set_type="assessments", - # flask_document_set_key="assessments", - # flask_query_set_element_type="assessment", - # flask_document_set_element_key="assessment", - # options=ConfigTestPatientSetOptions( - # set_id_will_already_exist=True, - # set_element_will_already_exist=True, - # ), - # ), - # ConfigTestPatientSet( - # name="assessmentlogs", - # semantic_set_id=scope.database.patient.assessment_logs.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_assessment_log_factory", - # document_factory_fixture_set="data_fake_assessment_logs_factory", - # database_get_set_function=scope.database.patient.assessment_logs.get_assessment_logs, - # database_get_function=scope.database.patient.assessment_logs.get_assessment_log, - # database_post_function=scope.database.patient.assessment_logs.post_assessment_log, - # database_unsafe_update_function=None, - # database_document_parameter_name="assessment_log", - # flask_query_set_type="assessmentlogs", - # flask_document_set_key="assessmentlogs", - # flask_query_set_element_type="assessmentlog", - # flask_document_set_element_key="assessmentlog", - # ), - # ConfigTestPatientSet( - # name="casereviews", - # semantic_set_id=scope.database.patient.case_reviews.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_case_review_factory", - # document_factory_fixture_set="data_fake_case_reviews_factory", - # database_get_set_function=scope.database.patient.case_reviews.get_case_reviews, - # database_get_function=scope.database.patient.case_reviews.get_case_review, - # database_post_function=scope.database.patient.case_reviews.post_case_review, - # database_unsafe_update_function=None, - # database_document_parameter_name="case_review", - # flask_query_set_type="casereviews", - # flask_document_set_key="casereviews", - # flask_query_set_element_type="casereview", - # flask_document_set_element_key="casereview", - # ), - # ConfigTestPatientSet( - # name="moodlogs", - # semantic_set_id=scope.database.patient.mood_logs.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_mood_log_factory", - # document_factory_fixture_set="data_fake_mood_logs_factory", - # database_get_set_function=scope.database.patient.mood_logs.get_mood_logs, - # database_get_function=scope.database.patient.mood_logs.get_mood_log, - # database_post_function=scope.database.patient.mood_logs.post_mood_log, - # database_unsafe_update_function=None, - # database_document_parameter_name="mood_log", - # flask_query_set_type="moodlogs", - # flask_document_set_key="moodlogs", - # flask_query_set_element_type="moodlog", - # flask_document_set_element_key="moodlog", - # ), + ConfigTestPatientSet( + name="activities", + semantic_set_id=scope.database.patient.activities.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_activity_factory", + document_factory_fixture_set="data_fake_activities_factory", + database_get_set_function=scope.database.patient.activities.get_activities, + database_get_function=scope.database.patient.activities.get_activity, + database_post_function=scope.database.patient.activities.post_activity, + database_unsafe_update_function=None, + database_document_parameter_name="activity", + flask_query_set_type="activities", + flask_document_set_key="activities", + flask_query_set_element_type="activity", + flask_document_set_element_key="activity", + options=ConfigTestPatientSetOptions( + set_supports_deletion=True, + ), + ), + ConfigTestPatientSet( + name="activitylogs", + semantic_set_id=scope.database.patient.activity_logs.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_activity_log_factory", + document_factory_fixture_set="data_fake_activity_logs_factory", + database_get_set_function=scope.database.patient.activity_logs.get_activity_logs, + database_get_function=scope.database.patient.activity_logs.get_activity_log, + database_post_function=scope.database.patient.activity_logs.post_activity_log, + database_unsafe_update_function=None, + database_document_parameter_name="activity_log", + flask_query_set_type="activitylogs", + flask_document_set_key="activitylogs", + flask_query_set_element_type="activitylog", + flask_document_set_element_key="activitylog", + ), + ConfigTestPatientSet( + name="activityschedules", + semantic_set_id=scope.database.patient.activity_schedules.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_activity_schedule_factory", + document_factory_fixture_set="data_fake_activity_schedules_factory", + database_get_set_function=scope.database.patient.activity_schedules.get_activity_schedules, + database_get_function=scope.database.patient.activity_schedules.get_activity_schedule, + database_post_function=scope.database.patient.activity_schedules.post_activity_schedule, + database_unsafe_update_function=None, + database_document_parameter_name="activity_schedule", + flask_query_set_type="activityschedules", + flask_document_set_key="activityschedules", + flask_query_set_element_type="activityschedule", + flask_document_set_element_key="activityschedule", + options=ConfigTestPatientSetOptions( + set_supports_deletion=True, + ), + ), + ConfigTestPatientSet( + name="assessments", + semantic_set_id=scope.database.patient.assessments.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_assessment_factory", + document_factory_fixture_set="data_fake_assessments_factory", + database_get_set_function=scope.database.patient.assessments.get_assessments, + database_get_function=scope.database.patient.assessments.get_assessment, + database_post_function=None, # Assessments have fixed set IDs + database_unsafe_update_function=scope.database.patient_unsafe_utils.unsafe_update_assessment, + database_document_parameter_name="assessment", + flask_query_set_type="assessments", + flask_document_set_key="assessments", + flask_query_set_element_type="assessment", + flask_document_set_element_key="assessment", + options=ConfigTestPatientSetOptions( + set_id_will_already_exist=True, + set_element_will_already_exist=True, + ), + ), + ConfigTestPatientSet( + name="assessmentlogs", + semantic_set_id=scope.database.patient.assessment_logs.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_assessment_log_factory", + document_factory_fixture_set="data_fake_assessment_logs_factory", + database_get_set_function=scope.database.patient.assessment_logs.get_assessment_logs, + database_get_function=scope.database.patient.assessment_logs.get_assessment_log, + database_post_function=scope.database.patient.assessment_logs.post_assessment_log, + database_unsafe_update_function=None, + database_document_parameter_name="assessment_log", + flask_query_set_type="assessmentlogs", + flask_document_set_key="assessmentlogs", + flask_query_set_element_type="assessmentlog", + flask_document_set_element_key="assessmentlog", + ), + ConfigTestPatientSet( + name="casereviews", + semantic_set_id=scope.database.patient.case_reviews.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_case_review_factory", + document_factory_fixture_set="data_fake_case_reviews_factory", + database_get_set_function=scope.database.patient.case_reviews.get_case_reviews, + database_get_function=scope.database.patient.case_reviews.get_case_review, + database_post_function=scope.database.patient.case_reviews.post_case_review, + database_unsafe_update_function=None, + database_document_parameter_name="case_review", + flask_query_set_type="casereviews", + flask_document_set_key="casereviews", + flask_query_set_element_type="casereview", + flask_document_set_element_key="casereview", + ), + ConfigTestPatientSet( + name="moodlogs", + semantic_set_id=scope.database.patient.mood_logs.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_mood_log_factory", + document_factory_fixture_set="data_fake_mood_logs_factory", + database_get_set_function=scope.database.patient.mood_logs.get_mood_logs, + database_get_function=scope.database.patient.mood_logs.get_mood_log, + database_post_function=scope.database.patient.mood_logs.post_mood_log, + database_unsafe_update_function=None, + database_document_parameter_name="mood_log", + flask_query_set_type="moodlogs", + flask_document_set_key="moodlogs", + flask_query_set_element_type="moodlog", + flask_document_set_element_key="moodlog", + ), ConfigTestPatientSet( name="reviewmarks", semantic_set_id=scope.database.patient.review_marks.SEMANTIC_SET_ID, @@ -207,73 +207,73 @@ class ConfigTestPatientSet: flask_query_set_element_type="reviewmark", flask_document_set_element_key="reviewmark", ), - # ConfigTestPatientSet( - # name="sessions", - # semantic_set_id=scope.database.patient.sessions.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_session_factory", - # document_factory_fixture_set="data_fake_sessions_factory", - # database_get_set_function=scope.database.patient.sessions.get_sessions, - # database_get_function=scope.database.patient.sessions.get_session, - # database_post_function=scope.database.patient.sessions.post_session, - # database_unsafe_update_function=None, - # database_document_parameter_name="session", - # flask_query_set_type="sessions", - # flask_document_set_key="sessions", - # flask_query_set_element_type="session", - # flask_document_set_element_key="session", - # ), - # ConfigTestPatientSet( - # name="scheduledactivities", - # semantic_set_id=scope.database.patient.scheduled_activities.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_scheduled_activity_factory", - # document_factory_fixture_set="data_fake_scheduled_activities_factory", - # database_get_set_function=scope.database.patient.scheduled_activities.get_scheduled_activities, - # database_get_function=scope.database.patient.scheduled_activities.get_scheduled_activity, - # database_post_function=scope.database.patient.scheduled_activities.post_scheduled_activity, - # database_unsafe_update_function=None, - # database_document_parameter_name="scheduled_activity", - # flask_query_set_type="scheduledactivities", - # flask_document_set_key="scheduledactivities", - # flask_query_set_element_type="scheduledactivity", - # flask_document_set_element_key="scheduledactivity", - # ), - # ConfigTestPatientSet( - # name="scheduledassessments", - # semantic_set_id=scope.database.patient.scheduled_assessments.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_scheduled_assessment_factory", - # document_factory_fixture_set="data_fake_scheduled_assessments_factory", - # database_get_set_function=scope.database.patient.scheduled_assessments.get_scheduled_assessments, - # database_get_function=scope.database.patient.scheduled_assessments.get_scheduled_assessment, - # database_post_function=scope.database.patient.scheduled_assessments.post_scheduled_assessment, - # database_unsafe_update_function=None, - # database_document_parameter_name="scheduled_assessment", - # flask_query_set_type="scheduledassessments", - # flask_document_set_key="scheduledassessments", - # flask_query_set_element_type="scheduledassessment", - # flask_document_set_element_key="scheduledassessment", - # options=ConfigTestPatientSetOptions( - # set_id_will_already_exist=False, - # set_element_will_already_exist=True, - # ), - # ), - # ConfigTestPatientSet( - # name="values", - # semantic_set_id=scope.database.patient.values.SEMANTIC_SET_ID, - # document_factory_fixture_set_element="data_fake_value_factory", - # document_factory_fixture_set="data_fake_values_factory", - # database_get_set_function=scope.database.patient.values.get_values, - # database_get_function=scope.database.patient.values.get_value, - # database_post_function=scope.database.patient.values.post_value, - # database_unsafe_update_function=None, - # database_document_parameter_name="value", - # flask_query_set_type="values", - # flask_document_set_key="values", - # flask_query_set_element_type="value", - # flask_document_set_element_key="value", - # options=ConfigTestPatientSetOptions( - # set_supports_deletion=True, - # ), - # ), + ConfigTestPatientSet( + name="sessions", + semantic_set_id=scope.database.patient.sessions.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_session_factory", + document_factory_fixture_set="data_fake_sessions_factory", + database_get_set_function=scope.database.patient.sessions.get_sessions, + database_get_function=scope.database.patient.sessions.get_session, + database_post_function=scope.database.patient.sessions.post_session, + database_unsafe_update_function=None, + database_document_parameter_name="session", + flask_query_set_type="sessions", + flask_document_set_key="sessions", + flask_query_set_element_type="session", + flask_document_set_element_key="session", + ), + ConfigTestPatientSet( + name="scheduledactivities", + semantic_set_id=scope.database.patient.scheduled_activities.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_scheduled_activity_factory", + document_factory_fixture_set="data_fake_scheduled_activities_factory", + database_get_set_function=scope.database.patient.scheduled_activities.get_scheduled_activities, + database_get_function=scope.database.patient.scheduled_activities.get_scheduled_activity, + database_post_function=scope.database.patient.scheduled_activities.post_scheduled_activity, + database_unsafe_update_function=None, + database_document_parameter_name="scheduled_activity", + flask_query_set_type="scheduledactivities", + flask_document_set_key="scheduledactivities", + flask_query_set_element_type="scheduledactivity", + flask_document_set_element_key="scheduledactivity", + ), + ConfigTestPatientSet( + name="scheduledassessments", + semantic_set_id=scope.database.patient.scheduled_assessments.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_scheduled_assessment_factory", + document_factory_fixture_set="data_fake_scheduled_assessments_factory", + database_get_set_function=scope.database.patient.scheduled_assessments.get_scheduled_assessments, + database_get_function=scope.database.patient.scheduled_assessments.get_scheduled_assessment, + database_post_function=scope.database.patient.scheduled_assessments.post_scheduled_assessment, + database_unsafe_update_function=None, + database_document_parameter_name="scheduled_assessment", + flask_query_set_type="scheduledassessments", + flask_document_set_key="scheduledassessments", + flask_query_set_element_type="scheduledassessment", + flask_document_set_element_key="scheduledassessment", + options=ConfigTestPatientSetOptions( + set_id_will_already_exist=False, + set_element_will_already_exist=True, + ), + ), + ConfigTestPatientSet( + name="values", + semantic_set_id=scope.database.patient.values.SEMANTIC_SET_ID, + document_factory_fixture_set_element="data_fake_value_factory", + document_factory_fixture_set="data_fake_values_factory", + database_get_set_function=scope.database.patient.values.get_values, + database_get_function=scope.database.patient.values.get_value, + database_post_function=scope.database.patient.values.post_value, + database_unsafe_update_function=None, + database_document_parameter_name="value", + flask_query_set_type="values", + flask_document_set_key="values", + flask_query_set_element_type="value", + flask_document_set_element_key="value", + options=ConfigTestPatientSetOptions( + set_supports_deletion=True, + ), + ), ] QUERY_SET = "patient/{patient_id}/{query_type}" diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 923dfed53..2d636dbb1 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -65,18 +65,18 @@ export interface IPatientStore extends IPatient { readonly recentEntryCutoffDateTime: Date | undefined; readonly recentEntryActivities: IActivity[] | undefined; readonly recentEntryActivityLogsSortedByDateAndTimeDescending: - | IActivityLog[] - | undefined; + | IActivityLog[] + | undefined; readonly recentEntryAssessmentLogsSortedByDateAndTimeDescending: - | IAssessmentLog[] - | undefined; + | IAssessmentLog[] + | undefined; readonly recentEntryMoodLogsSortedByDateAndTimeDescending: - | IMoodLog[] - | undefined; + | IMoodLog[] + | undefined; readonly recentEntrySafetyPlan: ISafetyPlan | undefined; readonly recentEntryScheduledActivitiesSortedByDateAndTimeDescending: - | IScheduledActivity[] - | undefined; + | IScheduledActivity[] + | undefined; readonly recentEntryValues: IValue[] | undefined; // UI states @@ -190,9 +190,7 @@ export class PatientStore implements IPatientStore { private readonly loadClinicalHistoryQuery: PromiseQuery; private readonly loadMoodLogsQuery: PromiseQuery; private readonly loadProfileQuery: PromiseQuery; - private readonly loadReviewMarksQuery: PromiseQuery< - IReviewMark[] - >; + private readonly loadReviewMarksQuery: PromiseQuery; private readonly loadSafetyPlanQuery: PromiseQuery; private readonly loadSessionsQuery: PromiseQuery; private readonly loadScheduledActivitiesQuery: PromiseQuery< @@ -481,7 +479,7 @@ export class PatientStore implements IPatientStore { this.recentEntryActivityLogsSortedByDateAndTimeDescending.length > 0) || (!!this.recentEntryAssessmentLogsSortedByDateAndTimeDescending && this.recentEntryAssessmentLogsSortedByDateAndTimeDescending.length > - 0) || + 0) || (!!this.recentEntryMoodLogsSortedByDateAndTimeDescending && this.recentEntryMoodLogsSortedByDateAndTimeDescending.length > 0) || !!this.recentEntrySafetyPlan || @@ -510,8 +508,7 @@ export class PatientStore implements IPatientStore { cutoffDateTime = this.reviewMarksSortedByDateAndTimeDescending.length > 0 - ? this.reviewMarksSortedByDateAndTimeDescending[0] - .effectiveDateTime + ? this.reviewMarksSortedByDateAndTimeDescending[0].effectiveDateTime : subDays(cutoffDateTime, 14); return cutoffDateTime; @@ -1229,10 +1226,10 @@ export class PatientStore implements IPatientStore { ), primaryCareManager: patientProfile.primaryCareManager ? { - name: patientProfile.primaryCareManager?.name, - providerId: patientProfile.primaryCareManager?.providerId, - role: patientProfile.primaryCareManager?.role, - } + name: patientProfile.primaryCareManager?.name, + providerId: patientProfile.primaryCareManager?.providerId, + role: patientProfile.primaryCareManager?.role, + } : undefined, }); diff --git a/web_shared/patientService.ts b/web_shared/patientService.ts index 9c1680c21..ce9b1e59e 100644 --- a/web_shared/patientService.ts +++ b/web_shared/patientService.ts @@ -125,9 +125,7 @@ export interface IPatientService extends IServiceBase { getMoodLogs(): Promise; addMoodLog(moodLog: IMoodLog): Promise; - addReviewMark( - reviewMark: IReviewMark, - ): Promise; + addReviewMark(reviewMark: IReviewMark): Promise; getValues(): Promise; addValue(value: IValue): Promise; @@ -588,9 +586,7 @@ class PatientService extends ServiceBase implements IPatientService { return response.data?.moodlog; } - public async addReviewMark( - reviewMark: IReviewMark, - ): Promise { + public async addReviewMark(reviewMark: IReviewMark): Promise { (reviewMark as any)._type = "reviewMark"; const response = await this.axiosInstance.post( diff --git a/web_shared/sorting.ts b/web_shared/sorting.ts index 3bdb6a462..2c416028d 100644 --- a/web_shared/sorting.ts +++ b/web_shared/sorting.ts @@ -25,13 +25,13 @@ export const sortingDirectionComparator: ( comparator, sortingDirection, ) { - switch (sortingDirection) { - case SortDirection.ASCENDING: - return comparator; - case SortDirection.DESCENDING: - return (compareA, compareB) => comparator(compareB, compareA); - } - }; + switch (sortingDirection) { + case SortDirection.ASCENDING: + return comparator; + case SortDirection.DESCENDING: + return (compareA, compareB) => comparator(compareB, compareA); + } +}; export const compareActivityByName: ( compareA: IActivity, @@ -137,15 +137,15 @@ export const sortActivitiesByDateAndTime: ( activities, sortingDirection = SortDirection.ASCENDING, ) { - return activities - .slice() - .sort( - sortingDirectionComparator( - compareActivitiesByDateAndTime, - sortingDirection, - ), - ); - }; + return activities + .slice() + .sort( + sortingDirectionComparator( + compareActivitiesByDateAndTime, + sortingDirection, + ), + ); +}; export const sortActivitiesByName: (activities: IActivity[]) => IActivity[] = function (activities) { @@ -159,15 +159,15 @@ export const sortActivityLogsByDateAndTime: ( activityLogs, sortingDirection = SortDirection.ASCENDING, ) { - return activityLogs - .slice() - .sort( - sortingDirectionComparator( - compareActivityLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return activityLogs + .slice() + .sort( + sortingDirectionComparator( + compareActivityLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortActivitySchedulesByDateAndTime: ( activitySchedules: IActivitySchedule[], @@ -182,15 +182,15 @@ export const sortAssessmentLogsByDateAndTime: ( assessmentLogs, sortingDirection = SortDirection.ASCENDING, ) { - return assessmentLogs - .slice() - .sort( - sortingDirectionComparator( - compareAssessmentLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return assessmentLogs + .slice() + .sort( + sortingDirectionComparator( + compareAssessmentLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortCaseReviewsByDate: ( caseReviews: ICaseReview[], @@ -205,15 +205,15 @@ export const sortCaseReviewsOrSessionsByDate: ( caseReviewsOrSessions, sortingDirection = SortDirection.ASCENDING, ) { - return caseReviewsOrSessions - .slice() - .sort( - sortingDirectionComparator( - compareCaseReviewsOrSessionsByDate, - sortingDirection, - ), - ); - }; + return caseReviewsOrSessions + .slice() + .sort( + sortingDirectionComparator( + compareCaseReviewsOrSessionsByDate, + sortingDirection, + ), + ); +}; export const sortMoodLogsByDateAndTime: ( moodLogs: IMoodLog[], @@ -222,15 +222,15 @@ export const sortMoodLogsByDateAndTime: ( moodLogs, sortingDirection = SortDirection.ASCENDING, ) { - return moodLogs - .slice() - .sort( - sortingDirectionComparator( - compareMoodLogsByDateAndTime, - sortingDirection, - ), - ); - }; + return moodLogs + .slice() + .sort( + sortingDirectionComparator( + compareMoodLogsByDateAndTime, + sortingDirection, + ), + ); +}; export const sortReviewMarksByDateAndTime: ( reviewMarks: IReviewMark[], @@ -239,15 +239,15 @@ export const sortReviewMarksByDateAndTime: ( reviewMarks, sortingDirection = SortDirection.ASCENDING, ) { - return reviewMarks - .slice() - .sort( - sortingDirectionComparator( - compareReviewMarksByDateAndTime, - sortingDirection, - ), - ); - }; + return reviewMarks + .slice() + .sort( + sortingDirectionComparator( + compareReviewMarksByDateAndTime, + sortingDirection, + ), + ); +}; export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities: IScheduledActivity[], @@ -256,15 +256,15 @@ export const sortScheduledActivitiesByDateAndTime: ( scheduledActivities, sortingDirection = SortDirection.ASCENDING, ) { - return scheduledActivities - .slice() - .sort( - sortingDirectionComparator( - compareScheduledActivitiesByDateAndTime, - sortingDirection, - ), - ); - }; + return scheduledActivities + .slice() + .sort( + sortingDirectionComparator( + compareScheduledActivitiesByDateAndTime, + sortingDirection, + ), + ); +}; export const sortSessionsByDate: (sessions: ISession[]) => ISession[] = function (sessions) { From e728bf18373b43b917ee62a8223a42dacc96b006 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Tue, 6 Aug 2024 19:14:53 -0700 Subject: [PATCH 08/26] Add reviewMarks to patient schema --- scope_shared/scope/schemas/api/patient.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scope_shared/scope/schemas/api/patient.json b/scope_shared/scope/schemas/api/patient.json index 0bbb784ac..4c0baab33 100644 --- a/scope_shared/scope/schemas/api/patient.json +++ b/scope_shared/scope/schemas/api/patient.json @@ -43,6 +43,11 @@ "description": "IPatientProfile schema", "$ref": "/schemas/documents/patient-profile" }, + "reviewMarks": { + "type": "object", + "description": "IReviewMark schema", + "$ref": "/schemas/documents/review-marks" + }, "safetyPlan": { "type": "object", "description": "ISafetyPlan schema", From 2e3818093c851776a76b3c97ed0601e8ea18a930 Mon Sep 17 00:00:00 2001 From: Anant Mittal Date: Wed, 7 Aug 2024 10:10:08 -0700 Subject: [PATCH 09/26] Fix patient schema, comments, and invoke format --- scope_shared/scope/schemas/api/patient.json | 2 -- server_flask/blueprints/registry/patients.py | 2 +- .../patient/test_patient_construct_patient_document.py | 3 +++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scope_shared/scope/schemas/api/patient.json b/scope_shared/scope/schemas/api/patient.json index 4c0baab33..eee9f2aa3 100644 --- a/scope_shared/scope/schemas/api/patient.json +++ b/scope_shared/scope/schemas/api/patient.json @@ -44,8 +44,6 @@ "$ref": "/schemas/documents/patient-profile" }, "reviewMarks": { - "type": "object", - "description": "IReviewMark schema", "$ref": "/schemas/documents/review-marks" }, "safetyPlan": { diff --git a/server_flask/blueprints/registry/patients.py b/server_flask/blueprints/registry/patients.py index a8794cf94..8cbc2ed8e 100644 --- a/server_flask/blueprints/registry/patients.py +++ b/server_flask/blueprints/registry/patients.py @@ -111,7 +111,7 @@ def _construct_patient_document( scope.database.patient.patient_profile.DOCUMENT_TYPE ] - # Recent Entry Reviews + # Review Marks patient_document["reviewMarks"] = documents_by_type[ scope.database.patient.review_marks.DOCUMENT_TYPE ] diff --git a/server_flask/tests/test_flask/patient/test_patient_construct_patient_document.py b/server_flask/tests/test_flask/patient/test_patient_construct_patient_document.py index 5b8c3682d..a85e36d0e 100644 --- a/server_flask/tests/test_flask/patient/test_patient_construct_patient_document.py +++ b/server_flask/tests/test_flask/patient/test_patient_construct_patient_document.py @@ -83,6 +83,9 @@ def test_patient_construct_patient_document( "profile": scope.database.patient.patient_profile.get_patient_profile( collection=patient_collection_current ), + "reviewMarks": scope.database.patient.review_marks.get_review_marks( + collection=patient_collection_current + ), "safetyPlan": scope.database.patient.safety_plan.get_safety_plan( collection=patient_collection_current ), From d11b1771136ae80fb8c00be7d80766ad673b8266 Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 06:56:25 -0700 Subject: [PATCH 10/26] Clarify Type Document and ensure field is required. It is already required in the underlying schema. --- web_shared/types.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_shared/types.ts b/web_shared/types.ts index 44da54ebc..5e4fa8c35 100644 --- a/web_shared/types.ts +++ b/web_shared/types.ts @@ -235,7 +235,10 @@ export interface IContact { export interface IReviewMark { editedDateTime: Date; effectiveDateTime: Date; - providerId?: string; + // ID of the provider that submitted the mark + // If these became more common, it would be necessary to decide + // on a meaning for "providerId" versus "submittedByProviderId". + providerId: string; } export interface ISafetyPlan { From fbee10a195d360f2ddc48698d04d74d092455abc Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 07:03:46 -0700 Subject: [PATCH 11/26] Clarify Review Mark Sort Criteria --- web_registry/src/components/common/ContentsMenu.tsx | 4 ++-- web_registry/src/stores/PatientStore.ts | 12 ++++++------ web_shared/sorting.ts | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index 23c8da82a..38891ebcd 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -151,7 +151,7 @@ export const ContentsMenu: FunctionComponent = observer( const onRecentEntryMarkUndo = action(() => { const previousReviewMark = - currentPatient.reviewMarksSortedByDateAndTimeDescending[1]; + currentPatient.reviewMarksSortedByEditedDateAndTimeDescending[1]; const { reviewMark } = markReviewState; currentPatient.addReviewMark({ ...reviewMark, @@ -320,7 +320,7 @@ export const ContentsMenu: FunctionComponent = observer( size="small" color="primary" disabled={ - currentPatient.reviewMarksSortedByDateAndTimeDescending + currentPatient.reviewMarksSortedByEditedDateAndTimeDescending .length <= 1 } startIcon={} diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 2d636dbb1..31630cb0f 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -21,7 +21,7 @@ import { sortCaseReviewsOrSessionsByDate, SortDirection, sortMoodLogsByDateAndTime, - sortReviewMarksByDateAndTime, + sortReviewMarksByEditedDateAndTime, sortScheduledActivitiesByDateAndTime, sortSessionsByDate, sortValuesByDateAndTime, @@ -113,7 +113,7 @@ export interface IPatientStore extends IPatient { readonly sessionsSortedByDate: ISession[]; readonly moodLogsSortedByDateAndTime: IMoodLog[]; readonly moodLogsSortedByDateAndTimeDescending: IMoodLog[]; - readonly reviewMarksSortedByDateAndTimeDescending: IReviewMark[]; + readonly reviewMarksSortedByEditedDateAndTimeDescending: IReviewMark[]; readonly scheduledActivitiesSortedByDateAndTimeDescending: IScheduledActivity[]; readonly valuesSortedByDateAndTimeDescending: IValue[]; @@ -392,8 +392,8 @@ export class PatientStore implements IPatientStore { return this.loadReviewMarksQuery.value || []; } - @computed get reviewMarksSortedByDateAndTimeDescending() { - return sortReviewMarksByDateAndTime( + @computed get reviewMarksSortedByEditedDateAndTimeDescending() { + return sortReviewMarksByEditedDateAndTime( this.reviewMarks, SortDirection.DESCENDING, ); @@ -507,8 +507,8 @@ export class PatientStore implements IPatientStore { // return this.profile.enrollmentDate; cutoffDateTime = - this.reviewMarksSortedByDateAndTimeDescending.length > 0 - ? this.reviewMarksSortedByDateAndTimeDescending[0].effectiveDateTime + this.reviewMarksSortedByEditedDateAndTimeDescending.length > 0 + ? this.reviewMarksSortedByEditedDateAndTimeDescending[0].effectiveDateTime : subDays(cutoffDateTime, 14); return cutoffDateTime; diff --git a/web_shared/sorting.ts b/web_shared/sorting.ts index 2c416028d..f11ad6326 100644 --- a/web_shared/sorting.ts +++ b/web_shared/sorting.ts @@ -92,7 +92,7 @@ export const compareMoodLogsByDateAndTime: ( return compareAsc(compareA.recordedDateTime, compareB.recordedDateTime); }; -export const compareReviewMarksByDateAndTime: ( +export const compareReviewMarksByEditedDateAndTime: ( compareA: IReviewMark, compareB: IReviewMark, ) => number = function (compareA, compareB): number { @@ -232,7 +232,7 @@ export const sortMoodLogsByDateAndTime: ( ); }; -export const sortReviewMarksByDateAndTime: ( +export const sortReviewMarksByEditedDateAndTime: ( reviewMarks: IReviewMark[], sortingDirection?: SortDirection, ) => IReviewMark[] = function ( @@ -243,7 +243,7 @@ export const sortReviewMarksByDateAndTime: ( .slice() .sort( sortingDirectionComparator( - compareReviewMarksByDateAndTime, + compareReviewMarksByEditedDateAndTime, sortingDirection, ), ); From 5c0cf98dd5ea961830b1802447f967bd825f036f Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 10:31:38 -0700 Subject: [PATCH 12/26] Test Fixture Cleanup --- .../scope/testing/fake_data/fixtures_fake_review_mark.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py index 110a84684..ab1080828 100644 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_review_mark.py @@ -2,7 +2,6 @@ import faker import pytest import pytz -import random from typing import Callable import scope.database.date_utils as date_utils @@ -10,7 +9,6 @@ import scope.enums import scope.schema import scope.schema_utils -import scope.testing.fake_data.fake_utils as fake_utils def fake_review_mark_factory( @@ -42,6 +40,7 @@ def factory() -> dict: ) ) ), + # TODO: this should be a providerId "providerId": faker_factory.name(), } From 19f79d582666f4075ab0117677fea99c58924945 Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 10:33:58 -0700 Subject: [PATCH 13/26] Text Fixture Cleanup --- .../scope/testing/fake_data/fixtures_fake_review_marks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py b/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py index a27ee8939..20b9b474d 100644 --- a/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py +++ b/scope_shared/scope/testing/fake_data/fixtures_fake_review_marks.py @@ -2,10 +2,8 @@ import random from typing import Callable, List -import scope.database.document_utils as document_utils import scope.schema import scope.schema_utils -import scope.testing.fake_data.fake_utils as fake_utils def fake_review_marks_factory( From 2a0c855f75ddbee995117398f1b127825648685d Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 10:58:50 -0700 Subject: [PATCH 14/26] Documentation Fix --- web_registry/src/stores/PatientStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 31630cb0f..359dd8554 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -169,7 +169,7 @@ export interface IPatientStore extends IPatient { // Patient profile updateProfile(profile: IPatientProfile): Promise; - // Recent entry review + // Review marks that define recent entry data addReviewMark(review: IReviewMark): Promise; // Session From 3f8b948651de43eec2af43c4791d3c03ec99314a Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Mon, 12 Aug 2024 15:34:48 -0700 Subject: [PATCH 15/26] Resolve Merge --- .../src/components/common/ContentsMenu.tsx | 20 ++--------------- web_registry/src/stores/PatientStore.ts | 22 +++++-------------- 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index 38891ebcd..e26bbe5bd 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -274,35 +274,19 @@ export const ContentsMenu: FunctionComponent = observer( ); }; - // return ( - //
- // - // - // CONTENTS - // {!!recentEntryCutoffDateTime && !!recentEntryBadgeContent && ( - // - // New Since: - //
- // {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} - //
- // )} - //
- //
- // {contents.map(createListItem)} - //
- // ); - return (
CONTENTS + {!!recentEntryCutoffDateTime && ( Last Reviewed:
{format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")}
+ )}
+ + +
{contents.map(createListItem)} From 6e081f19163195126ab4c87943d44573df3e4c44 Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Tue, 13 Aug 2024 15:59:53 -0700 Subject: [PATCH 21/26] Cutoff is Now Always Defined --- web_registry/src/stores/PatientStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_registry/src/stores/PatientStore.ts b/web_registry/src/stores/PatientStore.ts index 74d64897d..c31b83e45 100644 --- a/web_registry/src/stores/PatientStore.ts +++ b/web_registry/src/stores/PatientStore.ts @@ -63,7 +63,7 @@ export interface IPatientStore extends IPatient { // Recent patient entry properties readonly recentEntryCaseloadSummary: string | undefined; - readonly recentEntryCutoffDateTime: Date | undefined; + readonly recentEntryCutoffDateTime: Date; readonly recentEntryActivities: IActivity[] | undefined; readonly recentEntryActivityLogsSortedByDateAndTimeDescending: | IActivityLog[] From 718b6bb22c189095475ddcac21c709106daf01c7 Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Tue, 13 Aug 2024 16:10:35 -0700 Subject: [PATCH 22/26] More of Now Always Defined --- web_registry/src/components/common/ContentsMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index 82da78532..cc51fb517 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -72,7 +72,7 @@ export interface IContentItem { export interface IContentsMenuProps { contents: IContentItem[]; contentId: string; - recentEntryCutoffDateTime: Date | undefined; + recentEntryCutoffDateTime: Date; recentEntryBadgeContent: React.ReactNode; } From 680e0ad7dfb59d5b9977006d1e24e2760b1188d8 Mon Sep 17 00:00:00 2001 From: James Fogarty Date: Tue, 13 Aug 2024 17:29:40 -0700 Subject: [PATCH 23/26] Provide Contents Menu Feedback - Feedback Shows How Cutoff Was Calculated - Feedback Modifies/Remove Undo Text --- .../src/components/common/ContentsMenu.tsx | 185 ++++++++++++++---- web_registry/src/stores/PatientStore.ts | 18 +- 2 files changed, 156 insertions(+), 47 deletions(-) diff --git a/web_registry/src/components/common/ContentsMenu.tsx b/web_registry/src/components/common/ContentsMenu.tsx index cc51fb517..00a6d765b 100644 --- a/web_registry/src/components/common/ContentsMenu.tsx +++ b/web_registry/src/components/common/ContentsMenu.tsx @@ -14,10 +14,11 @@ import { useTheme, } from "@mui/material"; import withTheme from "@mui/styles/withTheme"; -import { compareAsc, format } from "date-fns"; +import { compareAsc, format, subDays } from "date-fns"; import throttle from "lodash.throttle"; import { action, observable } from "mobx"; import { observer, useLocalObservable } from "mobx-react"; +import { toLocalDateOnly } from "shared/time"; import { IReviewMark } from "shared/types"; import { getString } from "src/services/strings"; import { usePatient, useStores } from "src/stores/stores"; @@ -287,6 +288,112 @@ export const ContentsMenu: FunctionComponent = observer( [], ); + const lastMarkFeedbackNodes = (() => { + const nodesReviewMarkEffectiveCutoff = { + feedbackNode: ( + + New Entries +
+ Since Previous Mark: +
+ {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} +
+ ), + undoNode: getString("recent_patient_entry_undo_previous_mark"), + }; + + const nodesEnrollmentDateCutoff = { + feedbackNode: ( + + New Entries +
+ Since Enrollment: +
+ {format(recentEntryCutoffDateTime, "MM/dd/yyyy")} +
+ ), + undoNode: undefined, + }; + + const nodesEnrollmentDateUnknownCutoff = { + feedbackNode: ( + + New Entries +
+ Since Enrollment +
+ ), + undoNode: undefined, + }; + + const nodesTwoWeeksCutoff = { + feedbackNode: ( + + New Entries Since: +
+ {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} +
+ ), + undoNode: "Show More", + }; + + // Any current mark. + const reviewMarkCurrent = + currentPatient.reviewMarksSortedByEditedDateAndTimeDescending.length > 0 + ? currentPatient.reviewMarksSortedByEditedDateAndTimeDescending[0] + : undefined; + + // The effectiveDateTime of any current mark. + const reviewMarkEffectiveCutoffDateTime = + !!reviewMarkCurrent && !!reviewMarkCurrent.effectiveDateTime + ? reviewMarkCurrent.effectiveDateTime + : undefined; + + // If there is a mark that defines an effectiveDateTime, that defined our the cutoff. + if (!!reviewMarkEffectiveCutoffDateTime) { + return nodesReviewMarkEffectiveCutoff; + } + + // A dateTime calculated from the stored enrollmentDate. + const enrollmentDateCutoffDateTime = !!currentPatient.profile + .enrollmentDate + ? toLocalDateOnly(currentPatient.profile.enrollmentDate) + : undefined; + + // A default cutoff of 2 weeks before now. + // This is already in local time. + const twoWeeksCutoffDateTime = subDays(new Date(), 14); + + // If there is a mark, but it does not define effectiveDateTime, a person has explicitly reverted. + // They want to see "more", so we will go as far back as we are able. + // If there is an enrollment date, use that. + // If there is not an enrollment date, use a date from before the study started. + if (!!reviewMarkCurrent) { + if (!!enrollmentDateCutoffDateTime) { + return nodesEnrollmentDateCutoff; + } else { + return nodesEnrollmentDateUnknownCutoff; + } + } + + // If there is no mark, we are guessing at some default. + // Prior to the deployment of marks, that default was "2 weeks". + // We do not want to suddenly show all data as "new" just because there is no mark. + // So if there is no mark, continue to use the "2 weeks" default. + // But if there is an enrollment date which is less than 2 weeks in the past, that is the effective cutoff. + if (!!enrollmentDateCutoffDateTime) { + if ( + compareAsc(enrollmentDateCutoffDateTime, twoWeeksCutoffDateTime) >= 0 + ) { + return nodesEnrollmentDateCutoff; + } else { + return nodesTwoWeeksCutoff; + } + } else { + return nodesTwoWeeksCutoff; + } + })(); + const createListItem = (content: IContentItem) => { return ( = observer( CONTENTS - {!!recentEntryCutoffDateTime && ( - - Last Marked Reviewed: -
- {format(recentEntryCutoffDateTime, "MM/dd/yyyy h:mm aaa")} -
+ {lastMarkFeedbackNodes.feedbackNode} + {!!lastMarkFeedbackNodes.undoNode && ( + )} -