Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ This project uses a user-facing changelog format.

### Added

- Koirien viralliset ja historialliset värikoodit säilyvät tuonnissa, näkyvät suomeksi ja ruotsiksi koiraprofiileissa ja ovat hallittavissa ylläpidon koiralomakkeella.

### Changed

### Fixed

- Uudelle koiralle voi valita vain tällä hetkellä käytössä olevan värin, mutta vanha piilotettu värikoodi säilyy koiraa muokattaessa.

### Removed

- Ylläpidon koiranäkymistä piilotettiin kasvattajatiedot, kunnes kasvattajan historiatiedon ja kennelrekisterin suhde on päätetty.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe("getAdminDogsAction", () => {
showCount: 4,
titlesText: null,
ekNo: 5588,
colorCode: 121,
note: null,
},
],
Expand Down Expand Up @@ -144,6 +145,7 @@ describe("getAdminDogsAction", () => {
showCount: 4,
titlesText: null,
ekNo: 5588,
colorCode: 121,
note: null,
},
],
Expand Down
146 changes: 146 additions & 0 deletions apps/web/app/api/admin/dogs/lookups/colors/__tests__/route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { NextRequest } from "next/server";
import { beforeEach, describe, expect, it, vi } from "vitest";

const {
listAdminDogColorOptionsMock,
getSessionCurrentUserMock,
toAdminUserContextMock,
} = vi.hoisted(() => ({
listAdminDogColorOptionsMock: vi.fn(),
getSessionCurrentUserMock: vi.fn(),
toAdminUserContextMock: vi.fn(),
}));

vi.mock("@beagle/server", () => ({
listAdminDogColorOptions: listAdminDogColorOptionsMock,
}));

vi.mock("@/lib/server/current-user", () => ({
getSessionCurrentUser: getSessionCurrentUserMock,
}));

vi.mock("@/lib/server/admin-user-context", () => ({
toAdminUserContext: toAdminUserContextMock,
}));

describe("admin dog color lookup api route", () => {
beforeEach(() => {
listAdminDogColorOptionsMock.mockReset();
getSessionCurrentUserMock.mockReset();
toAdminUserContextMock.mockReset();
});

it("returns CORS preflight responses", async () => {
const { OPTIONS } = await import("../route");
const request = new NextRequest(
"http://localhost/api/admin/dogs/lookups/colors",
{
headers: { origin: "http://localhost:3000" },
},
);

const response = await OPTIONS(request);

expect(response.status).toBe(204);
});

it("returns color options for admins", async () => {
getSessionCurrentUserMock.mockResolvedValue({
id: "u_1",
email: "admin@example.com",
name: "Admin",
role: "ADMIN",
});
toAdminUserContextMock.mockReturnValue({
id: "u_1",
email: "admin@example.com",
username: "admin",
role: "ADMIN",
});
listAdminDogColorOptionsMock.mockResolvedValue({
status: 200,
body: {
ok: true,
data: {
items: [
{
code: 121,
nameFi: "Kolmivärinen",
nameSv: "Trefärgad",
nameEn: null,
status: "SELECTABLE",
},
],
},
},
});

const { GET } = await import("../route");
const request = new NextRequest(
"http://localhost/api/admin/dogs/lookups/colors",
{
headers: { origin: "http://localhost:3000" },
},
);
const response = await GET(request);

expect(response.status).toBe(200);
await expect(response.json()).resolves.toEqual({
ok: true,
data: {
items: [
{
code: 121,
nameFi: "Kolmivärinen",
nameSv: "Trefärgad",
nameEn: null,
status: "SELECTABLE",
},
],
},
});
expect(listAdminDogColorOptionsMock).toHaveBeenCalledWith({
id: "u_1",
email: "admin@example.com",
username: "admin",
role: "ADMIN",
});
});

it("returns structured errors when the server use case fails", async () => {
getSessionCurrentUserMock.mockResolvedValue({
id: "u_2",
email: "admin@example.com",
name: "Admin",
role: "ADMIN",
});
toAdminUserContextMock.mockReturnValue({
id: "u_2",
email: "admin@example.com",
username: "admin",
role: "ADMIN",
});
listAdminDogColorOptionsMock.mockResolvedValue({
status: 500,
body: {
ok: false,
error: "Failed to load dog color options.",
code: "INTERNAL_ERROR",
},
});

const { GET } = await import("../route");
const response = await GET(
new NextRequest("http://localhost/api/admin/dogs/lookups/colors", {
headers: { origin: "http://localhost:3000" },
}),
);

expect(response.status).toBe(500);
await expect(response.json()).resolves.toEqual({
ok: false,
error: "Failed to load dog color options.",
code: "INTERNAL_ERROR",
});
});
});
39 changes: 39 additions & 0 deletions apps/web/app/api/admin/dogs/lookups/colors/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { NextRequest } from "next/server";
import { listAdminDogColorOptions } from "@beagle/server";
import { getSessionCurrentUser } from "@/lib/server/current-user";
import { toAdminUserContext } from "@/lib/server/admin-user-context";
import { jsonResponse, optionsResponse } from "@/lib/server/cors";

export async function OPTIONS(request: NextRequest) {
return optionsResponse("GET,OPTIONS", {
origin: request.headers.get("origin"),
});
}

export async function GET(request: NextRequest) {
try {
const currentUser = await getSessionCurrentUser();
const result = await listAdminDogColorOptions(
toAdminUserContext(currentUser),
);

return jsonResponse(result.body, {
status: result.status,
methods: "GET,OPTIONS",
origin: request.headers.get("origin"),
});
} catch {
return jsonResponse(
{
ok: false,
error: "Failed to load dog color options.",
code: "INTERNAL_ERROR",
},
{
status: 500,
methods: "GET,OPTIONS",
origin: request.headers.get("origin"),
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { AdminDogFormValues } from "../types";

const {
useAdminDogsQueryMock,
useAdminDogColorOptionsQueryMock,
useAdminDogOwnerOptionsQueryMock,
useAdminDogParentOptionsQueryMock,
useCalculateAdminDogInbreedingMutationMock,
Expand All @@ -18,6 +19,7 @@ const {
dogResultsPropsMock,
} = vi.hoisted(() => ({
useAdminDogsQueryMock: vi.fn(),
useAdminDogColorOptionsQueryMock: vi.fn(),
useAdminDogOwnerOptionsQueryMock: vi.fn(),
useAdminDogParentOptionsQueryMock: vi.fn(),
useCalculateAdminDogInbreedingMutationMock: vi.fn(),
Expand All @@ -43,6 +45,7 @@ vi.mock("@/hooks/admin/dogs/manage", () => ({

vi.mock("@/queries/admin/dogs", () => ({
useAdminDogsQuery: useAdminDogsQueryMock,
useAdminDogColorOptionsQuery: useAdminDogColorOptionsQueryMock,
useAdminDogOwnerOptionsQuery: useAdminDogOwnerOptionsQueryMock,
useAdminDogParentOptionsQuery: useAdminDogParentOptionsQueryMock,
useCalculateAdminDogInbreedingMutation:
Expand Down Expand Up @@ -110,6 +113,7 @@ function buildFormValues(): AdminDogFormValues {
ownershipNames: ["Tiina Virtanen"],
ekNo: "5588",
inbreedingCoefficientPct: null,
colorCode: "121",
note: "",
registrationNo: "FI12345/21",
secondaryRegistrationNos: [],
Expand All @@ -124,6 +128,7 @@ function buildFormValues(): AdminDogFormValues {
describe("AdminDogsPageClient", () => {
beforeEach(() => {
useAdminDogsQueryMock.mockReset();
useAdminDogColorOptionsQueryMock.mockReset();
useAdminDogOwnerOptionsQueryMock.mockReset();
useAdminDogParentOptionsQueryMock.mockReset();
useCalculateAdminDogInbreedingMutationMock.mockReset();
Expand Down Expand Up @@ -171,6 +176,7 @@ describe("AdminDogsPageClient", () => {
showCount: 1,
titlesText: null,
ekNo: 5588,
colorCode: 121,
note: null,
titles: [],
},
Expand All @@ -179,6 +185,17 @@ describe("AdminDogsPageClient", () => {
isLoading: false,
isError: false,
});
useAdminDogColorOptionsQueryMock.mockReturnValue({
data: [
{
code: 121,
nameFi: "Kolmivärinen",
nameSv: "Trefärgad",
nameEn: null,
status: "SELECTABLE",
},
],
});
useAdminDogOwnerOptionsQueryMock.mockReturnValue({
data: [{ id: "o_1", name: "Tiina Virtanen" }],
});
Expand Down Expand Up @@ -259,6 +276,13 @@ describe("AdminDogsPageClient", () => {
{ registrationNo: "FI77777/18", name: "Havupolun Helmi" },
{ registrationNo: "FI54321/20", name: "Korven Aatos" },
]);
expect(dogFormProps.colorOptions).toEqual([
{
value: "121",
label: "121 - Kolmivärinen",
keywords: ["121", "Kolmivärinen", "Trefärgad", ""],
},
]);
expect(dogResultsProps.dogs[0]?.titlesText).toBeNull();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function buildEditValues(): AdminDogFormValues {
ownershipNames: ["Tiina Virtanen", "Antti Virtanen"],
ekNo: "5588",
inbreedingCoefficientPct: null,
colorCode: "121",
note: "Important note",
registrationNo: "FI12345/21",
secondaryRegistrationNos: ["FI54321/21"],
Expand All @@ -72,6 +73,7 @@ function buildCreateValues(): AdminDogFormValues {
ownershipNames: [],
ekNo: "",
inbreedingCoefficientPct: null,
colorCode: "",
note: "",
registrationNo: "",
secondaryRegistrationNos: [],
Expand Down Expand Up @@ -104,6 +106,7 @@ function buildDog(values: AdminDogFormValues): AdminDogRecord {
titlesText:
values.titles.map((title) => title.titleCode).join(", ") || null,
ekNo: Number(values.ekNo),
colorCode: values.colorCode ? Number(values.colorCode) : null,
note: values.note,
registrationNo: values.registrationNo,
secondaryRegistrationNos: values.secondaryRegistrationNos,
Expand All @@ -125,6 +128,7 @@ describe("DogFormModal", () => {
mode: "edit",
dog: buildDog(values),
values,
colorOptions: [{ value: "121", label: "121 - Kolmivärinen" }],
ownerOptions: [
{ id: "o_1", name: "Tiina Virtanen" },
{ id: "o_2", name: "Antti Virtanen" },
Expand Down Expand Up @@ -170,6 +174,7 @@ describe("DogFormModal", () => {
mode: "edit",
dog: buildDog(values),
values,
colorOptions: [{ value: "121", label: "121 - Kolmivärinen" }],
ownerOptions: [
{ id: "o_1", name: "Tiina Virtanen" },
{ id: "o_2", name: "Antti Virtanen" },
Expand Down Expand Up @@ -198,6 +203,7 @@ describe("DogFormModal", () => {
mode: "create",
dog: null,
values,
colorOptions: [],
ownerOptions: [],
parentOptions: [],
onOwnerSearchChange: vi.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function buildDog(overrides: Partial<AdminDogRecord> = {}): AdminDogRecord {
titlesText: "FI JVA, SE JCH",
ownershipPreview: ["Tiina Virtanen"],
ekNo: 5588,
colorCode: 121,
note: "Important",
sirePreview: { name: "Korven Aatos", registrationNo: "FI54321/20" },
damPreview: { name: "Havupolun Helmi", registrationNo: "FI77777/18" },
Expand Down
Loading
Loading