diff --git a/app/features/associations/core/Association.test.ts b/app/features/associations/core/Association.test.ts index 9ade813c4..a3004663d 100644 --- a/app/features/associations/core/Association.test.ts +++ b/app/features/associations/core/Association.test.ts @@ -181,3 +181,44 @@ describe("isVisible", () => { expect(Association.isVisible(args)).toBe(true); }); }); + +describe("mentionsAssociation", () => { + test.each([ + { why: "no visibility", visibility: null, expected: false }, + { + why: "current association", + visibility: { forAssociation: 1 }, + expected: true, + }, + { + why: "other association", + visibility: { forAssociation: 2 }, + expected: false, + }, + { + why: "virtual association", + visibility: { forAssociation: "+1" as const }, + expected: false, + }, + { + why: "association later in the schedule", + visibility: { + forAssociation: 2, + notFoundInstructions: [{ at: 0, forAssociation: 1 }], + }, + expected: true, + }, + { + why: "schedule going public only", + visibility: { + forAssociation: 2, + notFoundInstructions: [{ at: 0, forAssociation: null }], + }, + expected: false, + }, + ])("$why", ({ visibility, expected }) => { + expect( + Association.mentionsAssociation({ visibility, associationId: 1 }), + ).toBe(expected); + }); +}); diff --git a/app/features/associations/core/Association.ts b/app/features/associations/core/Association.ts index 58f518635..fe1f5d457 100644 --- a/app/features/associations/core/Association.ts +++ b/app/features/associations/core/Association.ts @@ -53,6 +53,24 @@ export function isVisible(args: IsVisibleArgs) { ); } +/** Whether the association is in the visibility at any point of its schedule, not only right now. */ +export function mentionsAssociation({ + visibility, + associationId, +}: { + visibility: AssociationVisibility | null; + associationId: number; +}) { + if (!visibility) return false; + + return ( + visibility.forAssociation === associationId || + (visibility.notFoundInstructions ?? []).some( + (instruction) => instruction.forAssociation === associationId, + ) + ); +} + export function isPublic(args: Omit) { return isVisible({ associations: null, diff --git a/app/features/associations/routes/associations.tsx b/app/features/associations/routes/associations.tsx index 83615d8de..aba7b6405 100644 --- a/app/features/associations/routes/associations.tsx +++ b/app/features/associations/routes/associations.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { useTranslation } from "react-i18next"; import { type MetaFunction, Outlet, useLoaderData } from "react-router"; import { ActionButton } from "~/components/ActionButton"; -import { SendouButton } from "~/components/elements/Button"; +import { LinkButton, SendouButton } from "~/components/elements/Button"; import { FormWithConfirm } from "~/components/FormWithConfirm"; import { Label } from "~/components/Label"; import { Main } from "~/components/Main"; @@ -16,6 +16,7 @@ import { loader, } from "~/features/associations/loaders/associations.server"; import { useUser } from "~/features/auth/core/user"; +import { scrimsByAssociationPage } from "~/features/scrims/scrims-urls"; import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; import { useHasPermission } from "~/modules/permissions/hooks"; import { metaTags } from "~/utils/remix"; @@ -133,35 +134,43 @@ function AssociationSection({ ?.username, })} - {!canManage || newAdmin ? ( - + - + {!canManage || newAdmin ? ( + - {t("scrims:associations.leave.action")} - - - ) : null} + + {t("scrims:associations.leave.action")} + + + ) : null} +
{association.members?.map((member) => ( users.id(1); +const otherUserId = () => users.id(2); +const requesterId = () => users.id(3); + +const scrimsLoader = wrappedLoader>({ loader }); + +describe("scrims loader", () => { + beforeEach(async () => { + await users.create(3); + }); + + const createAssociation = () => + AssociationFactory.create( + { userId: otherUserId() }, + { memberUserIds: [viewerId()] }, + ); + + const loadFilteredByAssociation = (associationId: number) => + scrimsLoader({ + user: viewerId(), + url: scrimsSearchParams.href(scrimsPage(), { associationId }), + }); + + test("only lists posts of the association filtered by", async () => { + const association = await createAssociation(); + + const { id: associationPostId } = await ScrimPostFactory.create({ + users: [{ userId: otherUserId(), isOwner: 1 }], + visibility: { forAssociation: association.id }, + }); + await ScrimPostFactory.create({ + users: [{ userId: otherUserId(), isOwner: 1 }], + }); + + const data = await loadFilteredByAssociation(association.id); + + expect(data.posts.neutral.map((post) => post.id)).toEqual([ + associationPostId, + ]); + }); + + test("keeps the viewer's own public post listed while filtering by association", async () => { + const association = await createAssociation(); + + const { id: ownPostId } = await ScrimPostFactory.create({ + users: [{ userId: viewerId(), isOwner: 1 }], + }); + + const data = await loadFilteredByAssociation(association.id); + + expect(data.posts.owned.map((post) => post.id)).toEqual([ownPostId]); + }); + + test("keeps a booked scrim listed while filtering by association", async () => { + const association = await createAssociation(); + + const { id: bookedPostId } = await ScrimPostFactory.create( + { + users: [{ userId: viewerId(), isOwner: 1 }], + }, + { + requests: [ + { + users: [{ userId: requesterId(), isOwner: 1 }], + isAccepted: true, + }, + ], + }, + ); + + const data = await loadFilteredByAssociation(association.id); + + expect(data.posts.booked.map((post) => post.id)).toEqual([bookedPostId]); + }); + + test("ignores a filter for an association the viewer is not in", async () => { + const otherAssociation = await AssociationFactory.create({ + userId: otherUserId(), + }); + + const { id: postId } = await ScrimPostFactory.create({ + users: [{ userId: otherUserId(), isOwner: 1 }], + }); + + const data = await loadFilteredByAssociation(otherAssociation.id); + + expect(data.associationFilter).toBeNull(); + expect(data.posts.neutral.map((post) => post.id)).toEqual([postId]); + }); +}); diff --git a/app/features/scrims/loaders/scrims.server.ts b/app/features/scrims/loaders/scrims.server.ts index 3fa2e7b00..0a6fd9e82 100644 --- a/app/features/scrims/loaders/scrims.server.ts +++ b/app/features/scrims/loaders/scrims.server.ts @@ -20,7 +20,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { ? await AssociationsRepository.findByMemberUserId(user?.id) : null; - const { weekdayTimes, weekendTimes, divs, useDefaults } = + const { weekdayTimes, weekendTimes, divs, useDefaults, associationId } = scrimsSearchParams.parse(request); const filtersFromSearchParams = { weekdayTimes, weekendTimes, divs }; @@ -31,26 +31,46 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { ? (user?.preferences?.defaultScrimsFilters ?? Scrim.defaultFilters()) : filtersFromSearchParams; - const posts = (await ScrimPostRepository.findAllRelevant()) - .filter( - (post) => - (user && Scrim.isParticipating(post, user.id)) || - Association.isVisible({ - associations, - visibility: post.visibility, - contentOwnerUserId: post.users.find((u) => u.isOwner)?.id, - }), - ) - .map((post) => ({ - ...post, - visibility: null, - isPrivate: !Association.isPublic({ + // a filter for an association the viewer is not in is ignored rather than showing an empty page + const associationFilter = + associations?.actual.find( + (association) => association.id === associationId, + ) ?? null; + + const visiblePosts = (await ScrimPostRepository.findAllRelevant()).filter( + (post) => + (user && Scrim.isParticipating(post, user.id)) || + Association.isVisible({ + associations, visibility: post.visibility, + contentOwnerUserId: post.users.find((u) => u.isOwner)?.id, }), - })); + ); + + const divided = dividePosts(visiblePosts, user?.id); + + // the association filter narrows browsing only, the viewer's own and booked posts stay listed + const dividedPosts = { + neutral: divided.neutral + .filter( + (post) => + !associationFilter || + Association.mentionsAssociation({ + visibility: post.visibility, + associationId: associationFilter.id, + }), + ) + .map(censorVisibility), + owned: divided.owned.map(censorVisibility), + booked: divided.booked.map(censorVisibility), + }; const cardUserIds = R.unique( - posts.flatMap((post) => [ + [ + ...dividedPosts.neutral, + ...dividedPosts.owned, + ...dividedPosts.booked, + ].flatMap((post) => [ ...post.users.map((postUser) => postUser.id), ...post.requests.flatMap((postRequest) => postRequest.users.map((requestUser) => requestUser.id), @@ -58,7 +78,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { ]), ); - const dividedPosts = dividePosts(posts, user?.id); const teams = user ? await TeamRepository.findAllByMemberUserId(user.id) : []; return { @@ -73,6 +92,14 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { viewerId: user?.id ?? null, }), filters, + associationFilter: associationFilter + ? { id: associationFilter.id, name: associationFilter.name } + : null, + associationOptions: + associations?.actual.map((association) => ({ + id: association.id, + name: association.name, + })) ?? [], canSaveAsDefault: user != null && !R.isDeepEqual( @@ -82,6 +109,17 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { }; }; +/** Replaces the raw visibility with a flag, so that association details do not reach the client. */ +function censorVisibility(post: ScrimPost): ScrimPost { + return { + ...post, + visibility: null, + isPrivate: !Association.isPublic({ + visibility: post.visibility, + }), + }; +} + /** How the viewer's teams relate to the requestable posts, one entry per post: what the fit indicators on cards and in the request dialog resolve from. */ async function rosterAvailability({ posts, diff --git a/app/features/scrims/routes/scrims.tsx b/app/features/scrims/routes/scrims.tsx index bbc4696b5..d868c5861 100644 --- a/app/features/scrims/routes/scrims.tsx +++ b/app/features/scrims/routes/scrims.tsx @@ -8,6 +8,7 @@ import * as R from "remeda"; import * as v from "valibot"; import { EmptyState } from "~/components/EmptyState"; import { LinkButton, SendouButton } from "~/components/elements/Button"; +import { SendouSelect, SendouSelectItem } from "~/components/elements/Select"; import { FilterBar } from "~/components/filter-bar/FilterBar"; import { LocaleTime } from "~/components/LocaleTime"; import { associationsPage } from "~/features/associations/associations-urls"; @@ -197,6 +198,35 @@ function Filters() { setParams({ ...filters, ...partial, useDefaults: false }); }; + const associationPill = + data.associationOptions.length > 0 + ? [ + { + key: "association", + name: t("scrims:filters.association"), + formattedValue: data.associationFilter?.name ?? null, + onRemove: () => setParams({ associationId: null }), + testId: "association-filter", + popover: ( + + setParams({ associationId: key as number | null }) + } + > + {({ id, name }) => ( + + {name} + + )} + + ), + }, + ] + : []; + return ( ), }, + ...associationPill, ]} onReset={ - !Scrim.filtersAreDefault(filters) + !Scrim.filtersAreDefault(filters) || data.associationFilter ? () => - writeFilters({ + setParams({ weekdayTimes: null, weekendTimes: null, divs: null, + associationId: null, + useDefaults: false, }) : undefined } diff --git a/app/features/scrims/scrims-search-params.test.ts b/app/features/scrims/scrims-search-params.test.ts index ebea18d3c..bb4ef7e7c 100644 --- a/app/features/scrims/scrims-search-params.test.ts +++ b/app/features/scrims/scrims-search-params.test.ts @@ -25,6 +25,7 @@ describe("scrimsSearchParams", () => { ], pendingRequestPostId: [null, 1, 987654], useDefaults: [true, false], + associationId: [null, 1, 42], }); }); @@ -49,5 +50,11 @@ describe("scrimsSearchParams", () => { ["-2"], ["1.5"], ]); + assertDecodesToDefault(scrimsSearchParams, "associationId", [ + ["abc"], + ["0"], + ["-2"], + ["1.5"], + ]); }); }); diff --git a/app/features/scrims/scrims-search-params.ts b/app/features/scrims/scrims-search-params.ts index 45122c437..96a504ec1 100644 --- a/app/features/scrims/scrims-search-params.ts +++ b/app/features/scrims/scrims-search-params.ts @@ -9,6 +9,11 @@ export const scrimsSearchParams = SearchParams.define({ divs: SP.custom(divsCodec, { loader: true }), /** False once the user has edited the filters, making the URL win over their saved defaults. */ useDefaults: SP.param(v.boolean(), { default: true, loader: true }), + /** Only posts whose visibility ever mentioned this association, not part of the saved default filters. */ + associationId: SP.param( + v.nullable(v.pipe(v.number(), v.integer(), v.gtValue(0))), + { loader: true }, + ), pendingRequestPostId: SP.param( v.nullable(v.pipe(v.number(), v.integer(), v.gtValue(0))), { diff --git a/app/features/scrims/scrims-urls.ts b/app/features/scrims/scrims-urls.ts new file mode 100644 index 000000000..156c786a0 --- /dev/null +++ b/app/features/scrims/scrims-urls.ts @@ -0,0 +1,5 @@ +import { scrimsPage } from "~/utils/urls"; +import { scrimsSearchParams } from "./scrims-search-params"; + +export const scrimsByAssociationPage = (associationId: number) => + scrimsSearchParams.href(scrimsPage(), { associationId }); diff --git a/changelog/2026-09-20-scrims-association-filter.md b/changelog/2026-09-20-scrims-association-filter.md new file mode 100644 index 000000000..388119aa7 --- /dev/null +++ b/changelog/2026-09-20-scrims-association-filter.md @@ -0,0 +1,5 @@ +--- +navItem: scrims +type: feature +--- +Scrims can be filtered by association, with a "View scrims" shortcut on the associations page diff --git a/locales/da/scrims.json b/locales/da/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/da/scrims.json +++ b/locales/da/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/de/scrims.json b/locales/de/scrims.json index d00d2fc95..8b4e638e5 100644 --- a/locales/de/scrims.json +++ b/locales/de/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "Assoziation {{name}} beitreten?", "associations.delete.title": "Assoziation {{name}} löschen?", "associations.admin": "Admin: {{username}}", + "associations.viewScrims": "", "associations.leave.title": "Assoziation {{name}} verlassen?", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "Verlassen", diff --git a/locales/en/scrims.json b/locales/en/scrims.json index cf3cfbef4..436bdfaa6 100644 --- a/locales/en/scrims.json +++ b/locales/en/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "Weekday times", "filters.weekendTimes": "Weekend times", "filters.divs": "Divs", + "filters.association": "Association", "filters.showFiltered": "Show filtered ({{count}})", "filters.hideFiltered": "Hide filtered ({{count}})", "filters.showPendingRequests": "Show pending requests ({{count}})", @@ -51,6 +52,7 @@ "associations.join.title": "Join {{name}} association?", "associations.delete.title": "Delete {{name}} association?", "associations.admin": "Admin: {{username}}", + "associations.viewScrims": "View scrims", "associations.leave.title": "Leave {{name}} association?", "associations.leave.titleWithNewAdmin": "Leave {{name}} association? {{username}} will become the new admin", "associations.leave.action": "Leave", diff --git a/locales/es-ES/scrims.json b/locales/es-ES/scrims.json index 8f9767ab0..5124a4bf9 100644 --- a/locales/es-ES/scrims.json +++ b/locales/es-ES/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "Horarios entre semana", "filters.weekendTimes": "Horarios de fin de semana", "filters.divs": "Divs", + "filters.association": "", "filters.showFiltered": "Mostrar filtrados ({{count}})", "filters.hideFiltered": "Ocultar filtrados ({{count}})", "filters.showPendingRequests": "Mostrar peticiones pendientes ({{count}})", @@ -51,6 +52,7 @@ "associations.join.title": "¿Unirse a la asociación {{name}}?", "associations.delete.title": "¿Eliminar la asociación {{name}}?", "associations.admin": "Administrador: {{username}}", + "associations.viewScrims": "", "associations.leave.title": "¿Salir de la asociación {{name}}?", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "Salir", diff --git a/locales/es-US/scrims.json b/locales/es-US/scrims.json index 8f9767ab0..5124a4bf9 100644 --- a/locales/es-US/scrims.json +++ b/locales/es-US/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "Horarios entre semana", "filters.weekendTimes": "Horarios de fin de semana", "filters.divs": "Divs", + "filters.association": "", "filters.showFiltered": "Mostrar filtrados ({{count}})", "filters.hideFiltered": "Ocultar filtrados ({{count}})", "filters.showPendingRequests": "Mostrar peticiones pendientes ({{count}})", @@ -51,6 +52,7 @@ "associations.join.title": "¿Unirse a la asociación {{name}}?", "associations.delete.title": "¿Eliminar la asociación {{name}}?", "associations.admin": "Administrador: {{username}}", + "associations.viewScrims": "", "associations.leave.title": "¿Salir de la asociación {{name}}?", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "Salir", diff --git a/locales/fr-CA/scrims.json b/locales/fr-CA/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/fr-CA/scrims.json +++ b/locales/fr-CA/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/fr-EU/scrims.json b/locales/fr-EU/scrims.json index 58fea6d1a..e1c4357e7 100644 --- a/locales/fr-EU/scrims.json +++ b/locales/fr-EU/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "Rejoindre l'association {{name}} ?", "associations.delete.title": "Supprimer l'association {{name}} ?", "associations.admin": "Admin: {{username}}", + "associations.viewScrims": "", "associations.leave.title": "Quitter l'association {{name}} ?", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "Quitter", diff --git a/locales/he/scrims.json b/locales/he/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/he/scrims.json +++ b/locales/he/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/it/scrims.json b/locales/it/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/it/scrims.json +++ b/locales/it/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/ja/scrims.json b/locales/ja/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/ja/scrims.json +++ b/locales/ja/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/ko/scrims.json b/locales/ko/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/ko/scrims.json +++ b/locales/ko/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/nl/scrims.json b/locales/nl/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/nl/scrims.json +++ b/locales/nl/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/pl/scrims.json b/locales/pl/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/pl/scrims.json +++ b/locales/pl/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/pt-BR/scrims.json b/locales/pt-BR/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/pt-BR/scrims.json +++ b/locales/pt-BR/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/ru/scrims.json b/locales/ru/scrims.json index fca64413d..9b7ea4e39 100644 --- a/locales/ru/scrims.json +++ b/locales/ru/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "", "filters.weekendTimes": "", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "", "filters.hideFiltered": "", "filters.showPendingRequests": "", @@ -51,6 +52,7 @@ "associations.join.title": "", "associations.delete.title": "", "associations.admin": "", + "associations.viewScrims": "", "associations.leave.title": "", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "", diff --git a/locales/zh/scrims.json b/locales/zh/scrims.json index fed6f4d1a..215a8aecf 100644 --- a/locales/zh/scrims.json +++ b/locales/zh/scrims.json @@ -14,6 +14,7 @@ "filters.weekdayTimes": "工作日时间", "filters.weekendTimes": "周末时间", "filters.divs": "", + "filters.association": "", "filters.showFiltered": "显示已过滤内容 ({{count}})", "filters.hideFiltered": "隐藏已过滤内容 ({{count}})", "filters.showPendingRequests": "显示待处理请求 ({{count}})", @@ -51,6 +52,7 @@ "associations.join.title": "加入群组 {{name}} ?", "associations.delete.title": "删除群组 {{name}} ?", "associations.admin": "管理员: {{username}}", + "associations.viewScrims": "", "associations.leave.title": "退出群组 {{name}} ?", "associations.leave.titleWithNewAdmin": "", "associations.leave.action": "退出",