Skip to content

adds rac contact details#228

Merged
HansKre merged 4 commits intodevelopfrom
darrell-roberts-agent-card-contact-details
Feb 19, 2026
Merged

adds rac contact details#228
HansKre merged 4 commits intodevelopfrom
darrell-roberts-agent-card-contact-details

Conversation

@DarrellRoberts
Copy link
Copy Markdown
Collaborator

Description

Adds Agent/RAC Contact Details

Related Issues

Closes issue 219

Changes

  • New hook for updating contact details
  • New component for RAC Contact Details

Screenshots / Demos

image image

As we don't have "role" and "landline" in the database yet, I had to mock a handler in the backend. Also I had some conflicts with the existing PATCH /person/:id, due to the lack of address on the form.

With this handler, you can successfully edit the details of: firstName, middleName, lastName, email and mobile.

However, if you want to successfully edit role or landline, you'll get a mock success response, but you won't be able to see the updated role/landline in the form.

src/server/routes/person.routes.ts

fastify.patch<{
    Params: ParamsId;
    Reply: ReplyData<ApiPersonGet>;
    Body: ApiPersonPatch;
  }>(
    "/:id",
    {
      schema: {
        params: idParamSchema,
        body: { $ref: "ApiPersonPatch#" },
        // response: responseSchema("ApiPersonGet#"),
        response: {
          200: {
            type: "object",
            properties: {
              message: { type: "string" },
              data: personResponseSchema,
            },
            required: ["message", "data"],
          },
        },
      },
    },
    async (request, reply) => {
      const personId = request.params.id;
      const body = request.body as any;

      if (body.role || body.landline) {
        const mockData = {
          id: personId,
          firstName: body.firstName || "Mock",
          lastName: body.lastName || "User", 
          ...body,
          updatedAt: new Date().toISOString(),
          createdAt: new Date().toISOString(), 
        };

        return reply.status(200).send({
          message: "Mock Update Successful",
          data: mockData,
        });
      } else {
        const person = await fastify.db.personRepository.findOne({
          where: { id: personId },
          // relations: ["address.postcode"],
          relations: [],
        });

        if (!person) {
          throw new NotFoundError(`Person with id ${personId} not found.`);
        }

        const updatedPersonObj = deepMerge(
          {
            id: person.id,
            // addressId: person.addressId,
            // address: { postcodeId: person.address.postcodeId },
          },
          dtoParsePerson(request.body),
        );

        const updatedPerson = await updatePerson(updatedPersonObj);

        const serializedData = dtoSerializePerson(updatedPerson);

        const data = {
          ...person,
          ...serializedData,
          address: null,
          createdAt: person.createdAt || new Date().toISOString(),
          updatedAt: new Date().toISOString(),
        };

        return reply
          .status(200)
          .send({ message: "Person updated successfully.", data });
      }
    },
  );

I added this to person entity for now:

src/data/entity/person.entity.ts

  @IsOptional()
  role?: string[];

  @IsOptional()
  @IsString()
  landline?: string;

I didn't add this, I just commented out any reference to the address in the updatePerson for now

src/server/utils/data/for-routes.ts

export async function updatePerson(
  person: DeepPartial<Person>,
): Promise<Person> {
  const personRepository = getRepository(dataSource, Person);

  // if (Object.keys(person.address || {}).length > 1) {
  //   await updateAddress(person.address);
  // }

  await personRepository.save(person);

  return (await personRepository.findOne({
    where: { id: person.id! },
    // relations: ["address.postcode"],
    relations: [],
  })) as Person;
}

I tweaked the Person Schema to include Role and Landline for now

src/server/schema/person.schema.ts

    role: { type: "string" },
    landline: { type: ["string", "null"] },
  },
};

Checklist

  • WITHIN THE SCOPE OF AN ISSUE; No unnecessary files included
  • Tests added/updated
  • Documentation updated
  • CI passes

@DarrellRoberts DarrellRoberts self-assigned this Feb 13, 2026
import { apiPathPerson } from "@/config/constants";
import { useParams } from "next/navigation";

export default function RacsPage() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of using /agents/:id instead? Is this the same as this page: src/app/[lang]/dashboard/agents/[id]/page.tsx?

@HansKre
Copy link
Copy Markdown
Collaborator

HansKre commented Feb 14, 2026

On another note: Since there is a contact details section for the volunteer as well as the opportunity, you might want to consider matching it. src/components/Dashboard/Profile/sections/ContactDetails/ContactDetails.tsx is a good starting point.

@DarrellRoberts DarrellRoberts force-pushed the darrell-roberts-agent-card-contact-details branch from 5baadcd to 65105b2 Compare February 16, 2026 11:14
@DarrellRoberts
Copy link
Copy Markdown
Collaborator Author

hey @HansKre , thank you for your feedback & both very good points. I've now rebased and refactored the agent contact details so that I'm using the /agents/:id page, useAgentProfileSection hook and the /ContactDetails/ContactDetails.tsx component

Copy link
Copy Markdown
Collaborator

@HansKre HansKre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. A few comments, only because codebase has changed quite a bit since you started working on the ticket. Sorry for the inconvenience.

gap: ${(props) => (props.$isEditing ? "var(--spacing-16)" : "0")};
`;

const Details = styled.div`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I ask you to move styled-components to styles.ts, to match established patterns and keep the actual component lean?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure thing, have done it now

width: 100%;
`;

const FieldWrapper = styled.div<{ $hasError?: boolean }>`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const FieldWrapper = styled.div<{ $hasError?: boolean }>`
const FieldWrapper = styled.div<HasError>`

import { AgentRoles } from "@/config/constants";
import { ApiAgentProfileGet } from "../../../types";

const Container = styled.div<{ $isEditing: boolean }>`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const Container = styled.div<{ $isEditing: boolean }>`
const Container = styled.div<IsEditing>`


const schema = createAgentContactDetailsSchema(t);

const initialFormValues = useMemo((): AgentContactDetailsFormData => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do something like:

Suggested change
const initialFormValues = useMemo((): AgentContactDetailsFormData => {
const initialFormValues = agent?.contactDetails;

Comment on lines +131 to +139
contactDetails: {
firstName: values.firstName,
lastName: values.lastName,
middleName: values.middleName,
role: values?.role?.length ? (values.role as AgentRoles[]) : undefined,
email: values.email,
phone: values.phone,
landline: values.landline,
},
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
contactDetails: {
firstName: values.firstName,
lastName: values.lastName,
middleName: values.middleName,
role: values?.role?.length ? (values.role as AgentRoles[]) : undefined,
email: values.email,
phone: values.phone,
landline: values.landline,
},
contactDetails: {
...values
},

return (
<Container $isEditing={isEditing}>
<Details>
{isEditing ? (
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I kindly ask to extract and move the editing- and displaying-components into separate files, as done in this PR #230?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for providing the PR, sure thing, I have refactored it now

phone: z
.string()
.min(1, t("dashboard.agentProfile.contactDetails.validation.mobileRequired"))
.regex(/^\+[0-9\s]+$/, t("dashboard.agentProfile.contactDetails.validation.mobileInvalid")),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea: could move this regex to somewhere central, so that it can be re-used here and in the other schemas

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I've moved it to src/config/constants.ts and also modified the phone schemas for agent, opportunity and volunteer to include it. Let me know what you think

@DarrellRoberts
Copy link
Copy Markdown
Collaborator Author

thank you @HansKre for checking, I've pushed my latest changes

Copy link
Copy Markdown
Collaborator

@HansKre HansKre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super clean and elegant 💪

@DarrellRoberts DarrellRoberts force-pushed the darrell-roberts-agent-card-contact-details branch from 5413a33 to 81c1c03 Compare February 18, 2026 19:39
@HansKre HansKre merged commit 64c8c3d into develop Feb 19, 2026
@HansKre HansKre deleted the darrell-roberts-agent-card-contact-details branch February 19, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants