mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-09 14:00:15 -04:00
Demo ready
This commit is contained in:
parent
ba15bf7519
commit
6d477678a9
|
@ -26,7 +26,7 @@ class ResourceEntity(EntityBase):
|
||||||
# set fields
|
# set fields
|
||||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||||
name: Mapped[str] = mapped_column(String(32), nullable=False)
|
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
summary: Mapped[str] = mapped_column(String(100), nullable=False)
|
summary: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||||
link: Mapped[str] = mapped_column(String, nullable=False)
|
link: Mapped[str] = mapped_column(String, nullable=False)
|
||||||
program: Mapped[Program_Enum] = mapped_column(Enum(Program_Enum), nullable=False)
|
program: Mapped[Program_Enum] = mapped_column(Enum(Program_Enum), nullable=False)
|
||||||
|
|
|
@ -22,6 +22,6 @@ entities.EntityBase.metadata.create_all(engine)
|
||||||
|
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
user_test_data.insert_test_data(session)
|
user_test_data.insert_test_data(session)
|
||||||
service_test_data.insert_fake_data(session)
|
service_test_data.insert_test_data(session)
|
||||||
resource_test_data.insert_fake_data(session)
|
resource_test_data.insert_test_data(session)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
|
@ -5,7 +5,7 @@ from ...entities import ResourceEntity
|
||||||
from ...models.enum_for_models import ProgramTypeEnum
|
from ...models.enum_for_models import ProgramTypeEnum
|
||||||
from ...models.resource_model import Resource
|
from ...models.resource_model import Resource
|
||||||
|
|
||||||
resource_1 = Resource(
|
resource1 = Resource(
|
||||||
id=1,
|
id=1,
|
||||||
name="Resource 1",
|
name="Resource 1",
|
||||||
summary="Helpful information for victims of domestic violence",
|
summary="Helpful information for victims of domestic violence",
|
||||||
|
@ -14,7 +14,7 @@ resource_1 = Resource(
|
||||||
created_at=datetime(2023, 6, 1, 10, 0, 0),
|
created_at=datetime(2023, 6, 1, 10, 0, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resource_2 = Resource(
|
resource2 = Resource(
|
||||||
id=2,
|
id=2,
|
||||||
name="Resource 2",
|
name="Resource 2",
|
||||||
summary="Legal assistance resources",
|
summary="Legal assistance resources",
|
||||||
|
@ -23,7 +23,7 @@ resource_2 = Resource(
|
||||||
created_at=datetime(2023, 6, 2, 12, 30, 0),
|
created_at=datetime(2023, 6, 2, 12, 30, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resource_3 = Resource(
|
resource3 = Resource(
|
||||||
id=3,
|
id=3,
|
||||||
name="Resource 3",
|
name="Resource 3",
|
||||||
summary="Financial aid resources",
|
summary="Financial aid resources",
|
||||||
|
@ -32,7 +32,7 @@ resource_3 = Resource(
|
||||||
created_at=datetime(2023, 6, 3, 15, 45, 0),
|
created_at=datetime(2023, 6, 3, 15, 45, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resource_4 = Resource(
|
resource4 = Resource(
|
||||||
id=4,
|
id=4,
|
||||||
name="Resource 4",
|
name="Resource 4",
|
||||||
summary="Counseling and support groups",
|
summary="Counseling and support groups",
|
||||||
|
@ -41,7 +41,7 @@ resource_4 = Resource(
|
||||||
created_at=datetime(2023, 6, 4, 9, 15, 0),
|
created_at=datetime(2023, 6, 4, 9, 15, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resource_5 = Resource(
|
resource5 = Resource(
|
||||||
id=5,
|
id=5,
|
||||||
name="Resource 5",
|
name="Resource 5",
|
||||||
summary="Shelter and housing resources",
|
summary="Shelter and housing resources",
|
||||||
|
@ -50,7 +50,210 @@ resource_5 = Resource(
|
||||||
created_at=datetime(2023, 6, 5, 11, 30, 0),
|
created_at=datetime(2023, 6, 5, 11, 30, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resources = [resource_1, resource_2, resource_3, resource_4, resource_5]
|
resources = [resource1, resource2, resource3, resource4, resource5]
|
||||||
|
|
||||||
|
resource_1 = Resource(
|
||||||
|
id=1,
|
||||||
|
name="National Domestic Violence Hotline",
|
||||||
|
summary="24/7 confidential support for victims of domestic violence",
|
||||||
|
link="https://www.thehotline.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 1, 10, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_2 = Resource(
|
||||||
|
id=2,
|
||||||
|
name="Legal Aid Society",
|
||||||
|
summary="Free legal assistance for low-income individuals",
|
||||||
|
link="https://www.legalaidnyc.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 2, 12, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_3 = Resource(
|
||||||
|
id=3,
|
||||||
|
name="Financial Empowerment Center",
|
||||||
|
summary="Free financial counseling and education services",
|
||||||
|
link="https://www1.nyc.gov/site/dca/consumers/get-free-financial-counseling.page",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 3, 15, 45, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_4 = Resource(
|
||||||
|
id=4,
|
||||||
|
name="National Coalition Against Domestic Violence",
|
||||||
|
summary="Resources and support for victims of domestic violence",
|
||||||
|
link="https://ncadv.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 4, 9, 15, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_5 = Resource(
|
||||||
|
id=5,
|
||||||
|
name="Safe Horizon",
|
||||||
|
summary="Shelter and support services for victims of violence",
|
||||||
|
link="https://www.safehorizon.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 5, 11, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_6 = Resource(
|
||||||
|
id=6,
|
||||||
|
name="National Sexual Assault Hotline",
|
||||||
|
summary="24/7 confidential support for survivors of sexual assault",
|
||||||
|
link="https://www.rainn.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 6, 14, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_7 = Resource(
|
||||||
|
id=7,
|
||||||
|
name="Victim Compensation Fund",
|
||||||
|
summary="Financial assistance for victims of crime",
|
||||||
|
link="https://ovc.ojp.gov/program/victim-compensation",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 7, 16, 45, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_8 = Resource(
|
||||||
|
id=8,
|
||||||
|
name="Battered Women's Justice Project",
|
||||||
|
summary="Legal and technical assistance for victims of domestic violence",
|
||||||
|
link="https://www.bwjp.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 8, 10, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_9 = Resource(
|
||||||
|
id=9,
|
||||||
|
name="National Network to End Domestic Violence",
|
||||||
|
summary="Advocacy and resources for ending domestic violence",
|
||||||
|
link="https://nnedv.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 9, 13, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_10 = Resource(
|
||||||
|
id=10,
|
||||||
|
name="Economic Justice Project",
|
||||||
|
summary="Promoting economic security for survivors of domestic violence",
|
||||||
|
link="https://www.njep.org",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 10, 15, 15, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_11 = Resource(
|
||||||
|
id=11,
|
||||||
|
name="Domestic Violence Legal Hotline",
|
||||||
|
summary="Free legal advice for victims of domestic violence",
|
||||||
|
link="https://www.womenslaw.org/find-help/national/hotlines",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 11, 9, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_12 = Resource(
|
||||||
|
id=12,
|
||||||
|
name="National Resource Center on Domestic Violence",
|
||||||
|
summary="Comprehensive information and resources on domestic violence",
|
||||||
|
link="https://nrcdv.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 12, 11, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_13 = Resource(
|
||||||
|
id=13,
|
||||||
|
name="Financial Assistance for Victims of Crime",
|
||||||
|
summary="Funding for expenses related to victimization",
|
||||||
|
link="https://ovc.ojp.gov/program/victim-assistance-funding",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 13, 14, 45, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_14 = Resource(
|
||||||
|
id=14,
|
||||||
|
name="National Clearinghouse for the Defense of Battered Women",
|
||||||
|
summary="Legal resources and support for battered women",
|
||||||
|
link="https://www.ncdbw.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 14, 10, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_15 = Resource(
|
||||||
|
id=15,
|
||||||
|
name="Victim Connect Resource Center",
|
||||||
|
summary="Referral helpline for crime victims",
|
||||||
|
link="https://victimconnect.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 15, 13, 15, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_16 = Resource(
|
||||||
|
id=16,
|
||||||
|
name="Economic Empowerment Program",
|
||||||
|
summary="Financial literacy and job readiness training for survivors",
|
||||||
|
link="https://www.purplepurse.com",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 16, 16, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_17 = Resource(
|
||||||
|
id=17,
|
||||||
|
name="National Domestic Violence Law Project",
|
||||||
|
summary="Legal information and resources for domestic violence survivors",
|
||||||
|
link="https://www.womenslaw.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 17, 9, 45, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_18 = Resource(
|
||||||
|
id=18,
|
||||||
|
name="Victim Rights Law Center",
|
||||||
|
summary="Free legal services for victims of sexual assault",
|
||||||
|
link="https://victimrights.org",
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
created_at=datetime(2023, 6, 18, 12, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_19 = Resource(
|
||||||
|
id=19,
|
||||||
|
name="Financial Justice Project",
|
||||||
|
summary="Advocating for economic justice for survivors of violence",
|
||||||
|
link="https://www.financialjusticeproject.org",
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
created_at=datetime(2023, 6, 19, 15, 30, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_20 = Resource(
|
||||||
|
id=20,
|
||||||
|
name="National Center on Domestic and Sexual Violence",
|
||||||
|
summary="Training and resources to end domestic and sexual violence",
|
||||||
|
link="http://www.ncdsv.org",
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
created_at=datetime(2023, 6, 20, 10, 15, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
resources1 = [
|
||||||
|
resource_1,
|
||||||
|
resource_2,
|
||||||
|
resource_3,
|
||||||
|
resource_4,
|
||||||
|
resource_5,
|
||||||
|
resource_6,
|
||||||
|
resource_7,
|
||||||
|
resource_8,
|
||||||
|
resource_9,
|
||||||
|
resource_10,
|
||||||
|
resource_11,
|
||||||
|
resource_12,
|
||||||
|
resource_13,
|
||||||
|
resource_14,
|
||||||
|
resource_15,
|
||||||
|
resource_16,
|
||||||
|
resource_17,
|
||||||
|
resource_18,
|
||||||
|
resource_19,
|
||||||
|
resource_20,
|
||||||
|
]
|
||||||
|
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.orm import Session, DeclarativeBase, InstrumentedAttribute
|
from sqlalchemy.orm import Session, DeclarativeBase, InstrumentedAttribute
|
||||||
|
@ -78,6 +281,23 @@ def reset_table_id_seq(
|
||||||
session.execute(sql)
|
session.execute(sql)
|
||||||
|
|
||||||
|
|
||||||
|
def insert_test_data(session: Session):
|
||||||
|
"""Inserts fake resource data into the test session."""
|
||||||
|
global resources1
|
||||||
|
# Create entities for test resource data
|
||||||
|
entities = []
|
||||||
|
for resource in resources1:
|
||||||
|
entity = ResourceEntity.from_model(resource)
|
||||||
|
session.add(entity)
|
||||||
|
entities.append(entity)
|
||||||
|
|
||||||
|
# Reset table IDs to prevent ID conflicts
|
||||||
|
reset_table_id_seq(session, ResourceEntity, ResourceEntity.id, len(resources1) + 1)
|
||||||
|
|
||||||
|
# Commit all changes
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
def insert_fake_data(session: Session):
|
def insert_fake_data(session: Session):
|
||||||
"""Inserts fake resource data into the test session."""
|
"""Inserts fake resource data into the test session."""
|
||||||
global resources
|
global resources
|
||||||
|
|
|
@ -46,8 +46,8 @@ def test_get_by_program(service_svc: ServiceService):
|
||||||
|
|
||||||
|
|
||||||
def test_create(service_svc: ServiceService):
|
def test_create(service_svc: ServiceService):
|
||||||
service = service_svc.create(user_test_data.admin, service_test_data.service_7)
|
service = service_svc.create(user_test_data.admin, service_test_data.service7)
|
||||||
assert service.name == service_test_data.service_7.name
|
assert service.name == service_test_data.service7.name
|
||||||
assert isinstance(service, Service)
|
assert isinstance(service, Service)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from ...entities import ServiceEntity
|
||||||
from ...models.enum_for_models import ProgramTypeEnum
|
from ...models.enum_for_models import ProgramTypeEnum
|
||||||
from ...models.service_model import Service
|
from ...models.service_model import Service
|
||||||
|
|
||||||
service_1 = Service(
|
service1 = Service(
|
||||||
id=1,
|
id=1,
|
||||||
name="service 1",
|
name="service 1",
|
||||||
status="open",
|
status="open",
|
||||||
|
@ -14,7 +14,7 @@ service_1 = Service(
|
||||||
program=ProgramTypeEnum.COMMUNITY,
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_2 = Service(
|
service2 = Service(
|
||||||
id=2,
|
id=2,
|
||||||
name="service 2",
|
name="service 2",
|
||||||
status="closed",
|
status="closed",
|
||||||
|
@ -23,7 +23,7 @@ service_2 = Service(
|
||||||
program=ProgramTypeEnum.DOMESTIC,
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_3 = Service(
|
service3 = Service(
|
||||||
id=3,
|
id=3,
|
||||||
name="service 3",
|
name="service 3",
|
||||||
status="open",
|
status="open",
|
||||||
|
@ -32,7 +32,7 @@ service_3 = Service(
|
||||||
program=ProgramTypeEnum.DOMESTIC,
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_4 = Service(
|
service4 = Service(
|
||||||
id=4,
|
id=4,
|
||||||
name="service 4",
|
name="service 4",
|
||||||
status="waitlist",
|
status="waitlist",
|
||||||
|
@ -41,7 +41,7 @@ service_4 = Service(
|
||||||
program=ProgramTypeEnum.COMMUNITY,
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_5 = Service(
|
service5 = Service(
|
||||||
id=5,
|
id=5,
|
||||||
name="service 5",
|
name="service 5",
|
||||||
status="open",
|
status="open",
|
||||||
|
@ -50,7 +50,7 @@ service_5 = Service(
|
||||||
program=ProgramTypeEnum.COMMUNITY,
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_6 = Service(
|
service6 = Service(
|
||||||
id=6,
|
id=6,
|
||||||
name="service 6",
|
name="service 6",
|
||||||
status="waitlist",
|
status="waitlist",
|
||||||
|
@ -68,7 +68,7 @@ service_6_edit = Service(
|
||||||
program=ProgramTypeEnum.ECONOMIC,
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
)
|
)
|
||||||
|
|
||||||
service_7 = Service(
|
service7 = Service(
|
||||||
id=7,
|
id=7,
|
||||||
name="service 7",
|
name="service 7",
|
||||||
status="waitlist",
|
status="waitlist",
|
||||||
|
@ -86,7 +86,210 @@ new_service = Service(
|
||||||
program=ProgramTypeEnum.DOMESTIC,
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
)
|
)
|
||||||
|
|
||||||
services = [service_1, service_2, service_3, service_4, service_5, service_6]
|
services = [service1, service2, service3, service6, service5, service6]
|
||||||
|
|
||||||
|
service_1 = Service(
|
||||||
|
id=1,
|
||||||
|
name="Crisis Hotline",
|
||||||
|
status="open",
|
||||||
|
summary="24/7 support for individuals in crisis",
|
||||||
|
requirements=["Anonymous", "Confidential"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_2 = Service(
|
||||||
|
id=2,
|
||||||
|
name="Shelter Placement",
|
||||||
|
status="open",
|
||||||
|
summary="Emergency shelter for victims of domestic violence",
|
||||||
|
requirements=["Referral required", "Safety assessment"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_3 = Service(
|
||||||
|
id=3,
|
||||||
|
name="Legal Advocacy",
|
||||||
|
status="waitlist",
|
||||||
|
summary="Legal support and representation for survivors",
|
||||||
|
requirements=["Intake required", "Income eligibility"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_4 = Service(
|
||||||
|
id=4,
|
||||||
|
name="Counseling Services",
|
||||||
|
status="open",
|
||||||
|
summary="Individual and group therapy for survivors",
|
||||||
|
requirements=["Initial assessment", "Insurance accepted"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_5 = Service(
|
||||||
|
id=5,
|
||||||
|
name="Financial Assistance",
|
||||||
|
status="open",
|
||||||
|
summary="Emergency funds for survivors in need",
|
||||||
|
requirements=["Application required", "Proof of income"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_6 = Service(
|
||||||
|
id=6,
|
||||||
|
name="Housing Assistance",
|
||||||
|
status="waitlist",
|
||||||
|
summary="Support for finding safe and affordable housing",
|
||||||
|
requirements=["Referral required", "Background check"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_7 = Service(
|
||||||
|
id=7,
|
||||||
|
name="Job Training",
|
||||||
|
status="open",
|
||||||
|
summary="Employment skills training for survivors",
|
||||||
|
requirements=["Enrollment required", "18+"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_8 = Service(
|
||||||
|
id=8,
|
||||||
|
name="Support Groups",
|
||||||
|
status="open",
|
||||||
|
summary="Peer support groups for survivors",
|
||||||
|
requirements=["Registration required", "Confidential"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_9 = Service(
|
||||||
|
id=9,
|
||||||
|
name="Children's Services",
|
||||||
|
status="open",
|
||||||
|
summary="Specialized services for children exposed to domestic violence",
|
||||||
|
requirements=["Parental consent", "Age-appropriate"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_10 = Service(
|
||||||
|
id=10,
|
||||||
|
name="Safety Planning",
|
||||||
|
status="open",
|
||||||
|
summary="Personalized safety planning for survivors",
|
||||||
|
requirements=["Confidential", "Collaborative"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_11 = Service(
|
||||||
|
id=11,
|
||||||
|
name="Community Education",
|
||||||
|
status="open",
|
||||||
|
summary="Workshops and training on domestic violence prevention",
|
||||||
|
requirements=["Open to the public", "Registration preferred"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_12 = Service(
|
||||||
|
id=12,
|
||||||
|
name="Healthcare Services",
|
||||||
|
status="open",
|
||||||
|
summary="Medical care and support for survivors",
|
||||||
|
requirements=["Referral required", "Insurance accepted"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_13 = Service(
|
||||||
|
id=13,
|
||||||
|
name="Transportation Assistance",
|
||||||
|
status="waitlist",
|
||||||
|
summary="Help with transportation for survivors",
|
||||||
|
requirements=["Eligibility assessment", "Limited availability"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_14 = Service(
|
||||||
|
id=14,
|
||||||
|
name="Court Accompaniment",
|
||||||
|
status="open",
|
||||||
|
summary="Support and advocacy during court proceedings",
|
||||||
|
requirements=["Legal case", "Scheduling required"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_15 = Service(
|
||||||
|
id=15,
|
||||||
|
name="Relocation Assistance",
|
||||||
|
status="waitlist",
|
||||||
|
summary="Support for relocating to a safe environment",
|
||||||
|
requirements=["Referral required", "Safety assessment"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_16 = Service(
|
||||||
|
id=16,
|
||||||
|
name="Parenting Classes",
|
||||||
|
status="open",
|
||||||
|
summary="Education and support for parents",
|
||||||
|
requirements=["Open to parents", "Pre-registration required"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_17 = Service(
|
||||||
|
id=17,
|
||||||
|
name="Life Skills Training",
|
||||||
|
status="open",
|
||||||
|
summary="Workshops on various life skills for survivors",
|
||||||
|
requirements=["Enrollment required", "Commitment to attend"],
|
||||||
|
program=ProgramTypeEnum.ECONOMIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_18 = Service(
|
||||||
|
id=18,
|
||||||
|
name="Advocacy Services",
|
||||||
|
status="open",
|
||||||
|
summary="Individual advocacy and support for survivors",
|
||||||
|
requirements=["Intake required", "Confidential"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_19 = Service(
|
||||||
|
id=19,
|
||||||
|
name="Volunteer Opportunities",
|
||||||
|
status="open",
|
||||||
|
summary="Various volunteer roles supporting the organization",
|
||||||
|
requirements=["Background check", "Training required"],
|
||||||
|
program=ProgramTypeEnum.COMMUNITY,
|
||||||
|
)
|
||||||
|
|
||||||
|
service_20 = Service(
|
||||||
|
id=20,
|
||||||
|
name="Referral Services",
|
||||||
|
status="open",
|
||||||
|
summary="Referrals to community resources and partner agencies",
|
||||||
|
requirements=["Intake required", "Based on individual needs"],
|
||||||
|
program=ProgramTypeEnum.DOMESTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
services1 = [
|
||||||
|
service_1,
|
||||||
|
service_2,
|
||||||
|
service_3,
|
||||||
|
service_4,
|
||||||
|
service_5,
|
||||||
|
service_6,
|
||||||
|
service_7,
|
||||||
|
service_8,
|
||||||
|
service_9,
|
||||||
|
service_10,
|
||||||
|
service_11,
|
||||||
|
service_12,
|
||||||
|
service_13,
|
||||||
|
service_14,
|
||||||
|
service_15,
|
||||||
|
service_16,
|
||||||
|
service_17,
|
||||||
|
service_18,
|
||||||
|
service_19,
|
||||||
|
service_20,
|
||||||
|
]
|
||||||
|
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.orm import Session, DeclarativeBase, InstrumentedAttribute
|
from sqlalchemy.orm import Session, DeclarativeBase, InstrumentedAttribute
|
||||||
|
@ -114,6 +317,24 @@ def reset_table_id_seq(
|
||||||
session.execute(sql)
|
session.execute(sql)
|
||||||
|
|
||||||
|
|
||||||
|
def insert_test_data(session: Session):
|
||||||
|
"""Inserts fake organization data into the test session."""
|
||||||
|
global services1
|
||||||
|
|
||||||
|
# Create entities for test organization data
|
||||||
|
entities = []
|
||||||
|
for service in services1:
|
||||||
|
entity = ServiceEntity.from_model(service)
|
||||||
|
session.add(entity)
|
||||||
|
entities.append(entity)
|
||||||
|
|
||||||
|
# Reset table IDs to prevent ID conflicts
|
||||||
|
reset_table_id_seq(session, ServiceEntity, ServiceEntity.id, len(services1) + 1)
|
||||||
|
|
||||||
|
# Commit all changes
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
def insert_fake_data(session: Session):
|
def insert_fake_data(session: Session):
|
||||||
"""Inserts fake organization data into the test session."""
|
"""Inserts fake organization data into the test session."""
|
||||||
global services
|
global services
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default function RootLayout({
|
||||||
console.log(
|
console.log(
|
||||||
`Accessed admin page but incorrect permissions: ${user.username} ${user.role}`
|
`Accessed admin page but incorrect permissions: ${user.username} ${user.role}`
|
||||||
);
|
);
|
||||||
router.push("/auth/login");
|
router.push("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
compass/app/api/resource/all/route.ts
Normal file
24
compass/app/api/resource/all/route.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import Resource from "@/utils/models/Resource";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/resource`;
|
||||||
|
|
||||||
|
console.log(apiEndpoint);
|
||||||
|
|
||||||
|
const { searchParams } = new URL(request.url);
|
||||||
|
const uuid = searchParams.get("uuid");
|
||||||
|
|
||||||
|
const data = await fetch(`${apiEndpoint}?user_id=${uuid}`);
|
||||||
|
|
||||||
|
const resourceData: Resource[] = await data.json();
|
||||||
|
// TODO: Remove make every resource visible
|
||||||
|
|
||||||
|
const resources = resourceData.map((resource: Resource) => {
|
||||||
|
resource.visible = true;
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(resources, { status: data.status });
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
return NextResponse.json({ message: "Hello World!" }, { status: 200 });
|
|
||||||
}
|
|
24
compass/app/api/service/all/route.ts
Normal file
24
compass/app/api/service/all/route.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import Service from "@/utils/models/Service";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/service`;
|
||||||
|
|
||||||
|
console.log(apiEndpoint);
|
||||||
|
|
||||||
|
const { searchParams } = new URL(request.url);
|
||||||
|
const uuid = searchParams.get("uuid");
|
||||||
|
|
||||||
|
const data = await fetch(`${apiEndpoint}?user_id=${uuid}`);
|
||||||
|
|
||||||
|
const serviceData: Service[] = await data.json();
|
||||||
|
// TODO: Remove make every service visible
|
||||||
|
|
||||||
|
const services = serviceData.map((service: Service) => {
|
||||||
|
service.visible = true;
|
||||||
|
|
||||||
|
return service;
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(services, { status: data.status });
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
return NextResponse.json({ message: "Hello World!" }, { status: 200 });
|
|
||||||
}
|
|
|
@ -1,18 +1,18 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import { Table } from "@/components/Table/Index";
|
import { ResourceTable } from "@/components/Table/ResourceIndex";
|
||||||
import User from "@/utils/models/User";
|
import Resource from "@/utils/models/Resource";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
|
||||||
import { UsersIcon } from "@heroicons/react/24/solid";
|
import { BookmarkIcon } from "@heroicons/react/24/solid";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [resources, setResources] = useState<Resource[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getUser() {
|
async function getResources() {
|
||||||
const supabase = createClient();
|
const supabase = createClient();
|
||||||
|
|
||||||
const { data, error } = await supabase.auth.getUser();
|
const { data, error } = await supabase.auth.getUser();
|
||||||
|
@ -23,22 +23,22 @@ export default function Page() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const userListData = await fetch(
|
const userListData = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_HOST}/api/user/all?uuid=${data.user.id}`
|
`${process.env.NEXT_PUBLIC_HOST}/api/resource/all?uuid=${data.user.id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const users: User[] = await userListData.json();
|
const resourcesAPI: Resource[] = await userListData.json();
|
||||||
|
|
||||||
setUsers(users);
|
setResources(resourcesAPI);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUser();
|
getResources();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
{/* icon + title */}
|
{/* icon + title */}
|
||||||
<PageLayout title="Users" icon={<UsersIcon />}>
|
<PageLayout title="Resources" icon={<BookmarkIcon />}>
|
||||||
<Table users={users} />
|
<ResourceTable users={resources} />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default function RootLayout({
|
||||||
console.log(data, error);
|
console.log(data, error);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log("Accessed admin page but not logged in");
|
console.log("Accessed service page but not logged in");
|
||||||
router.push("/auth/login");
|
router.push("/auth/login");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -38,14 +38,6 @@ export default function RootLayout({
|
||||||
|
|
||||||
const user: User = await userData.json();
|
const user: User = await userData.json();
|
||||||
|
|
||||||
if (user.role !== Role.ADMIN) {
|
|
||||||
console.log(
|
|
||||||
`Accessed admin page but incorrect permissions: ${user.username} ${user.role}`
|
|
||||||
);
|
|
||||||
router.push("/auth/login");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(user);
|
setUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import { Table } from "@/components/Table/Index";
|
import { ServiceTable } from "@/components/Table/ServiceIndex";
|
||||||
import User from "@/utils/models/User";
|
import Service from "@/utils/models/Service";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
|
||||||
import { UsersIcon } from "@heroicons/react/24/solid";
|
import { ClipboardIcon } from "@heroicons/react/24/solid";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [services, setUsers] = useState<Service[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getUser() {
|
async function getServices() {
|
||||||
const supabase = createClient();
|
const supabase = createClient();
|
||||||
|
|
||||||
const { data, error } = await supabase.auth.getUser();
|
const { data, error } = await supabase.auth.getUser();
|
||||||
|
@ -22,23 +22,22 @@ export default function Page() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userListData = await fetch(
|
const serviceListData = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_HOST}/api/user/all?uuid=${data.user.id}`
|
`${process.env.NEXT_PUBLIC_HOST}/api/service/all?uuid=${data.user.id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const users: User[] = await userListData.json();
|
const servicesAPI: Service[] = await serviceListData.json();
|
||||||
|
setUsers(servicesAPI);
|
||||||
setUsers(users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getUser();
|
getServices();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
{/* icon + title */}
|
{/* icon + title */}
|
||||||
<PageLayout title="Users" icon={<UsersIcon />}>
|
<PageLayout title="Services" icon={<ClipboardIcon />}>
|
||||||
<Table users={users} />
|
<ServiceTable users={services} />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -32,7 +32,7 @@ import {
|
||||||
} from "@heroicons/react/24/solid";
|
} from "@heroicons/react/24/solid";
|
||||||
import TagsInput from "../TagsInput/Index";
|
import TagsInput from "../TagsInput/Index";
|
||||||
import { rankItem } from "@tanstack/match-sorter-utils";
|
import { rankItem } from "@tanstack/match-sorter-utils";
|
||||||
import User from "@/utils/models/User";
|
import Resource from "@/utils/models/Resource";
|
||||||
|
|
||||||
// For search
|
// For search
|
||||||
const fuzzyFilter = (
|
const fuzzyFilter = (
|
||||||
|
@ -51,8 +51,9 @@ const fuzzyFilter = (
|
||||||
return itemRank.passed;
|
return itemRank.passed;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Table = ({ users }: { users: User[] }) => {
|
// TODO: Rename everything to resources
|
||||||
const columnHelper = createColumnHelper<User>();
|
export const ResourceTable = ({ users }: { users: Resource[] }) => {
|
||||||
|
const columnHelper = createColumnHelper<Resource>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const sortedUsers = [...users].sort((a, b) =>
|
const sortedUsers = [...users].sort((a, b) =>
|
||||||
|
@ -114,15 +115,15 @@ export const Table = ({ users }: { users: User[] }) => {
|
||||||
id: "options",
|
id: "options",
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<RowOptionMenu
|
<RowOptionMenu
|
||||||
onDelete={() => deleteUser(props.row.original.id)}
|
onDelete={() => {}}
|
||||||
onHide={() => hideUser(props.row.original.id)}
|
onHide={() => hideUser(props.row.original.id)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("username", {
|
columnHelper.accessor("name", {
|
||||||
header: () => (
|
header: () => (
|
||||||
<>
|
<>
|
||||||
<Bars2Icon className="inline align-top h-4" /> Username
|
<Bars2Icon className="inline align-top h-4" /> Name
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
cell: (info) => (
|
cell: (info) => (
|
||||||
|
@ -133,47 +134,44 @@ export const Table = ({ users }: { users: User[] }) => {
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("role", {
|
columnHelper.accessor("link", {
|
||||||
header: () => (
|
header: () => (
|
||||||
<>
|
<>
|
||||||
<ArrowDownCircleIcon className="inline align-top h-4" />{" "}
|
<Bars2Icon className="inline align-top h-4" /> Link
|
||||||
Role
|
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
cell: (info) => (
|
cell: (info) => (
|
||||||
<TagsInput
|
<a
|
||||||
presetValue={info.getValue()}
|
href={info.getValue()}
|
||||||
presetOptions={presetOptions}
|
target={"_blank"}
|
||||||
setPresetOptions={setPresetOptions}
|
className="ml-2 text-gray-500 underline hover:text-gray-400"
|
||||||
getTagColor={getTagColor}
|
>
|
||||||
setTagColors={setTagColors}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
columnHelper.accessor("email", {
|
|
||||||
header: () => (
|
|
||||||
<>
|
|
||||||
<AtSymbolIcon className="inline align-top h-4" /> Email
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
cell: (info) => (
|
|
||||||
<span className="ml-2 text-gray-500 underline hover:text-gray-400">
|
|
||||||
{info.getValue()}
|
{info.getValue()}
|
||||||
</span>
|
</a>
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("program", {
|
columnHelper.accessor("program", {
|
||||||
header: () => (
|
header: () => (
|
||||||
<>
|
<>
|
||||||
<ArrowDownCircleIcon className="inline align-top h-4" />{" "}
|
<Bars2Icon className="inline align-top h-4" /> Program
|
||||||
Program
|
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
cell: (info) => <TagsInput presetValue={info.getValue()} />,
|
cell: (info) => <TagsInput presetValue={info.getValue()} />,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
columnHelper.accessor("summary", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Summary
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<span className="ml-2 text-gray-500">{info.getValue()}</span>
|
||||||
|
),
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const [data, setData] = useState<User[]>([...users]);
|
const [data, setData] = useState<Resource[]>([...users]);
|
||||||
|
|
||||||
const addUser = () => {
|
const addUser = () => {
|
||||||
setData([...data]);
|
setData([...data]);
|
||||||
|
@ -196,7 +194,7 @@ export const Table = ({ users }: { users: User[] }) => {
|
||||||
// TODO: Sorting
|
// TODO: Sorting
|
||||||
|
|
||||||
// added this fn for editing rows
|
// added this fn for editing rows
|
||||||
const handleRowUpdate = (updatedRow: User) => {
|
const handleRowUpdate = (updatedRow: Resource) => {
|
||||||
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
||||||
if (dataIndex !== -1) {
|
if (dataIndex !== -1) {
|
||||||
const updatedData = [...data];
|
const updatedData = [...data];
|
||||||
|
|
312
compass/components/Table/ServiceIndex.tsx
Normal file
312
compass/components/Table/ServiceIndex.tsx
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
// for showcasing to compass
|
||||||
|
|
||||||
|
import users from "./users.json";
|
||||||
|
import {
|
||||||
|
Cell,
|
||||||
|
ColumnDef,
|
||||||
|
Row,
|
||||||
|
createColumnHelper,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
|
sortingFns,
|
||||||
|
useReactTable,
|
||||||
|
} from "@tanstack/react-table";
|
||||||
|
import {
|
||||||
|
ChangeEvent,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
FunctionComponent,
|
||||||
|
useRef,
|
||||||
|
ChangeEventHandler,
|
||||||
|
Key,
|
||||||
|
} from "react";
|
||||||
|
import { RowOptionMenu } from "./RowOptionMenu";
|
||||||
|
import { RowOpenAction } from "./RowOpenAction";
|
||||||
|
import { TableAction } from "./TableAction";
|
||||||
|
import {
|
||||||
|
AtSymbolIcon,
|
||||||
|
Bars2Icon,
|
||||||
|
ArrowDownCircleIcon,
|
||||||
|
PlusIcon,
|
||||||
|
} from "@heroicons/react/24/solid";
|
||||||
|
import TagsInput from "../TagsInput/Index";
|
||||||
|
import { rankItem } from "@tanstack/match-sorter-utils";
|
||||||
|
import Service from "@/utils/models/Service";
|
||||||
|
|
||||||
|
// For search
|
||||||
|
const fuzzyFilter = (
|
||||||
|
row: Row<any>,
|
||||||
|
columnId: string,
|
||||||
|
value: any,
|
||||||
|
addMeta: (meta: any) => void
|
||||||
|
) => {
|
||||||
|
// Rank the item
|
||||||
|
const itemRank = rankItem(row.getValue(columnId), value);
|
||||||
|
|
||||||
|
// Store the ranking info
|
||||||
|
addMeta(itemRank);
|
||||||
|
|
||||||
|
// Return if the item should be filtered in/out
|
||||||
|
return itemRank.passed;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Rename everything to service
|
||||||
|
export const ServiceTable = ({ users }: { users: Service[] }) => {
|
||||||
|
const columnHelper = createColumnHelper<Service>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const sortedUsers = [...users].sort((a, b) =>
|
||||||
|
a.visible === b.visible ? 0 : a.visible ? -1 : 1
|
||||||
|
);
|
||||||
|
setData(sortedUsers);
|
||||||
|
}, [users]);
|
||||||
|
|
||||||
|
const deleteUser = (userId: number) => {
|
||||||
|
console.log(data);
|
||||||
|
setData((currentData) =>
|
||||||
|
currentData.filter((user) => user.id !== userId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideUser = (userId: number) => {
|
||||||
|
console.log(`Toggling visibility for user with ID: ${userId}`);
|
||||||
|
setData((currentData) => {
|
||||||
|
const newData = currentData
|
||||||
|
.map((user) => {
|
||||||
|
if (user.id === userId) {
|
||||||
|
return { ...user, visible: !user.visible };
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
})
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.visible === b.visible ? 0 : a.visible ? -1 : 1
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(newData);
|
||||||
|
return newData;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const [presetOptions, setPresetOptions] = useState([
|
||||||
|
"administrator",
|
||||||
|
"volunteer",
|
||||||
|
"employee",
|
||||||
|
]);
|
||||||
|
const [tagColors, setTagColors] = useState(new Map());
|
||||||
|
|
||||||
|
const getTagColor = (tag: string) => {
|
||||||
|
if (!tagColors.has(tag)) {
|
||||||
|
const colors = [
|
||||||
|
"bg-cyan-100",
|
||||||
|
"bg-blue-100",
|
||||||
|
"bg-green-100",
|
||||||
|
"bg-yellow-100",
|
||||||
|
"bg-purple-100",
|
||||||
|
];
|
||||||
|
const randomColor =
|
||||||
|
colors[Math.floor(Math.random() * colors.length)];
|
||||||
|
setTagColors(new Map(tagColors).set(tag, randomColor));
|
||||||
|
}
|
||||||
|
return tagColors.get(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
columnHelper.display({
|
||||||
|
id: "options",
|
||||||
|
cell: (props) => (
|
||||||
|
<RowOptionMenu
|
||||||
|
onDelete={() => {}}
|
||||||
|
onHide={() => hideUser(props.row.original.id)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("name", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Name
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<RowOpenAction
|
||||||
|
title={info.getValue()}
|
||||||
|
rowData={info.row.original}
|
||||||
|
onRowUpdate={handleRowUpdate}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("status", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Status
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<span className="ml-2 text-gray-500">{info.getValue()}</span>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("program", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Program
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => <TagsInput presetValue={info.getValue()} />,
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("requirements", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Requirements
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<TagsInput
|
||||||
|
presetValue={
|
||||||
|
info.getValue()[0] !== "" ? info.getValue() : ["N/A"]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
|
||||||
|
columnHelper.accessor("summary", {
|
||||||
|
header: () => (
|
||||||
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Summary
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<span className="ml-2 text-gray-500">{info.getValue()}</span>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const [data, setData] = useState<Service[]>([...users]);
|
||||||
|
|
||||||
|
const addUser = () => {
|
||||||
|
setData([...data]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Searching
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
|
const handleSearchChange = (e: ChangeEvent) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
setQuery(String(target.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCellChange = (e: ChangeEvent, key: Key) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
console.log(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Filtering
|
||||||
|
|
||||||
|
// TODO: Sorting
|
||||||
|
|
||||||
|
// added this fn for editing rows
|
||||||
|
const handleRowUpdate = (updatedRow: Service) => {
|
||||||
|
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
||||||
|
if (dataIndex !== -1) {
|
||||||
|
const updatedData = [...data];
|
||||||
|
updatedData[dataIndex] = updatedRow;
|
||||||
|
setData(updatedData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const table = useReactTable({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
filterFns: {
|
||||||
|
fuzzy: fuzzyFilter,
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
globalFilter: query,
|
||||||
|
},
|
||||||
|
onGlobalFilterChange: setQuery,
|
||||||
|
globalFilterFn: fuzzyFilter,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleRowData = (row: any) => {
|
||||||
|
const rowData: any = {};
|
||||||
|
row.cells.forEach((cell: any) => {
|
||||||
|
rowData[cell.column.id] = cell.value;
|
||||||
|
});
|
||||||
|
// Use rowData object containing data from all columns for the current row
|
||||||
|
console.log(rowData);
|
||||||
|
return rowData;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="flex flex-row justify-end">
|
||||||
|
<TableAction query={query} handleChange={handleSearchChange} />
|
||||||
|
</div>
|
||||||
|
<table className="w-full text-xs text-left rtl:text-right">
|
||||||
|
<thead className="text-xs text-gray-500 capitalize">
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<tr key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header, i) => (
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
className={
|
||||||
|
"p-2 border-gray-200 border-y font-medium " +
|
||||||
|
(1 < i && i < columns.length - 1
|
||||||
|
? "border-x"
|
||||||
|
: "")
|
||||||
|
}
|
||||||
|
key={header.id}
|
||||||
|
>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(
|
||||||
|
header.column.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{table.getRowModel().rows.map((row) => {
|
||||||
|
// Individual row
|
||||||
|
const isUserVisible = row.original.visible;
|
||||||
|
const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${
|
||||||
|
!isUserVisible ? "bg-gray-200 text-gray-500" : ""
|
||||||
|
}`;
|
||||||
|
return (
|
||||||
|
<tr className={rowClassNames} key={row.id}>
|
||||||
|
{row.getVisibleCells().map((cell, i) => (
|
||||||
|
<td
|
||||||
|
key={cell.id}
|
||||||
|
className={
|
||||||
|
"[&:nth-child(n+3)]:border-x relative first:text-left first:px-0 last:border-none"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="p-3 border-y border-gray-200 text-gray-600 hover:bg-gray-50"
|
||||||
|
colSpan={100}
|
||||||
|
onClick={addUser}
|
||||||
|
>
|
||||||
|
<span className="flex ml-1 text-gray-500">
|
||||||
|
<PlusIcon className="inline h-4 mr-1" />
|
||||||
|
New
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -6,6 +6,9 @@ import { CreateNewTagAction } from "./CreateNewTagAction";
|
||||||
|
|
||||||
interface TagsInputProps {
|
interface TagsInputProps {
|
||||||
presetOptions: string[];
|
presetOptions: string[];
|
||||||
|
presetValue: string | string[];
|
||||||
|
setPresetOptions: () => {};
|
||||||
|
getTagColor: () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagsInput: React.FC<TagsInputProps> = ({
|
const TagsInput: React.FC<TagsInputProps> = ({
|
||||||
|
@ -34,8 +37,12 @@ const TagsInput: React.FC<TagsInputProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOutsideClick = (event) => {
|
// TODO: Fix MouseEvent type and remove the as Node as that is completely wrong
|
||||||
if (dropdown.current && !dropdown.current.contains(event.target)) {
|
const handleOutsideClick = (event: MouseEvent) => {
|
||||||
|
if (
|
||||||
|
dropdown.current &&
|
||||||
|
!dropdown.current.contains(event.target as Node)
|
||||||
|
) {
|
||||||
setCellSelected(false);
|
setCellSelected(false);
|
||||||
// Remove event listener after handling outside click
|
// Remove event listener after handling outside click
|
||||||
window.removeEventListener("click", handleOutsideClick);
|
window.removeEventListener("click", handleOutsideClick);
|
||||||
|
@ -117,7 +124,11 @@ const TagsInput: React.FC<TagsInputProps> = ({
|
||||||
return (
|
return (
|
||||||
<div className="cursor-pointer" onClick={handleClick}>
|
<div className="cursor-pointer" onClick={handleClick}>
|
||||||
{!cellSelected ? (
|
{!cellSelected ? (
|
||||||
<TagsArray handleDelete={handleDeleteTag} tags={tags} />
|
<TagsArray
|
||||||
|
active={true}
|
||||||
|
handleDelete={handleDeleteTag}
|
||||||
|
tags={tags}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div ref={dropdown}>
|
<div ref={dropdown}>
|
||||||
<div className="absolute w-64 z-50 ml-1 mt-5">
|
<div className="absolute w-64 z-50 ml-1 mt-5">
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Tag } from "./Tag";
|
import { Tag } from "./Tag";
|
||||||
|
|
||||||
export interface Tags {
|
export interface Tags {
|
||||||
tags: string[];
|
tags: Set<string>;
|
||||||
handleDelete: () => {};
|
handleDelete: (tag: string) => void;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
79
compass/package-lock.json
generated
79
compass/package-lock.json
generated
|
@ -13,9 +13,12 @@
|
||||||
"@supabase/supabase-js": "^2.42.3",
|
"@supabase/supabase-js": "^2.42.3",
|
||||||
"@tanstack/match-sorter-utils": "^8.15.1",
|
"@tanstack/match-sorter-utils": "^8.15.1",
|
||||||
"@tanstack/react-table": "^8.15.0",
|
"@tanstack/react-table": "^8.15.0",
|
||||||
|
"bufferutil": "^4.0.8",
|
||||||
"next": "13.5.6",
|
"next": "13.5.6",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18"
|
"react-dom": "^18",
|
||||||
|
"utf-8-validate": "^6.0.3",
|
||||||
|
"ws": "^8.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
@ -572,26 +575,6 @@
|
||||||
"ws": "^8.14.2"
|
"ws": "^8.14.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@supabase/realtime-js/node_modules/ws": {
|
|
||||||
"version": "8.16.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
|
|
||||||
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"utf-8-validate": ">=5.0.2"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"bufferutil": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"utf-8-validate": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@supabase/ssr": {
|
"node_modules/@supabase/ssr": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -2973,6 +2956,18 @@
|
||||||
"browserslist": ">= 4.21.0"
|
"browserslist": ">= 4.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bufferutil": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/busboy": {
|
"node_modules/busboy": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||||
|
@ -7236,6 +7231,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
@ -8229,6 +8234,18 @@
|
||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/utf-8-validate": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||||
|
@ -8279,6 +8296,26 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
|
||||||
|
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
"@supabase/supabase-js": "^2.42.3",
|
"@supabase/supabase-js": "^2.42.3",
|
||||||
"@tanstack/match-sorter-utils": "^8.15.1",
|
"@tanstack/match-sorter-utils": "^8.15.1",
|
||||||
"@tanstack/react-table": "^8.15.0",
|
"@tanstack/react-table": "^8.15.0",
|
||||||
|
"bufferutil": "^4.0.8",
|
||||||
"next": "13.5.6",
|
"next": "13.5.6",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18"
|
"react-dom": "^18",
|
||||||
|
"utf-8-validate": "^6.0.3",
|
||||||
|
"ws": "^8.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
|
11
compass/utils/models/Resource.ts
Normal file
11
compass/utils/models/Resource.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { Program } from "./User";
|
||||||
|
|
||||||
|
export default interface Resource {
|
||||||
|
id: number;
|
||||||
|
created_at: Date;
|
||||||
|
name: string;
|
||||||
|
summary: string;
|
||||||
|
link: string;
|
||||||
|
program: Program;
|
||||||
|
visible: boolean;
|
||||||
|
}
|
12
compass/utils/models/Service.ts
Normal file
12
compass/utils/models/Service.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Program } from "./User";
|
||||||
|
|
||||||
|
export default interface Service {
|
||||||
|
id: number;
|
||||||
|
created_at: Date;
|
||||||
|
name: string;
|
||||||
|
status: string;
|
||||||
|
summary: string;
|
||||||
|
requirements: string[];
|
||||||
|
program: Program;
|
||||||
|
visible: boolean;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user