feat(admin): ban appeals, photos polish, economy adjust, staff smoke
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
fe46bd0544
commit
3ad3f9512c
36 files changed
+1185
-293
No files matched your search
@@ -31,6 +31,53 @@ function revalidateHelpCenterTicketPaths(ticketId: bigint) {
|
|||||||
revalidatePath(`/help/tickets/${id}`);
|
revalidatePath(`/help/tickets/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const liftBanFromHelpTicket = adminAction(
|
||||||
|
{
|
||||||
|
permission: PERMS.USERS_BAN,
|
||||||
|
schema: helpCenterTicketIdSchema,
|
||||||
|
},
|
||||||
|
async (ctx) => {
|
||||||
|
const ticketId = ctx.data.ticketId;
|
||||||
|
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
|
||||||
|
where: { id: ticketId },
|
||||||
|
select: { id: true, userId: true, open: true, title: true },
|
||||||
|
});
|
||||||
|
if (!ticket) throw new ActionError("Ticket not found");
|
||||||
|
if (ticket.userId == null) {
|
||||||
|
throw new ActionError("Ticket has no requester to unban");
|
||||||
|
}
|
||||||
|
|
||||||
|
const removed = await prisma.ban.deleteMany({
|
||||||
|
where: { userId: ticket.userId },
|
||||||
|
});
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
if (ticket.open) {
|
||||||
|
await prisma.websiteHelpCenterTickets.update({
|
||||||
|
where: { id: ticketId },
|
||||||
|
data: { open: false, updatedAt: now },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logAudit({
|
||||||
|
userId: ctx.session.user.id,
|
||||||
|
action: "unban_via_help_ticket",
|
||||||
|
target: "User",
|
||||||
|
targetId: ticket.userId,
|
||||||
|
after: {
|
||||||
|
ticketId: String(ticketId),
|
||||||
|
removedBans: removed.count,
|
||||||
|
title: ticket.title,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
revalidateHelpCenterTicketPaths(ticketId);
|
||||||
|
revalidatePath("/admin/bans");
|
||||||
|
revalidatePath(`/admin/users/show/${ticket.userId}`);
|
||||||
|
return actionOk({ removed: removed.count, userId: ticket.userId });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const HELP_TICKET_EDIT = [PERMS.TICKETS_EDIT, PERMS.MOD_TICKETS_EDIT] as const;
|
const HELP_TICKET_EDIT = [PERMS.TICKETS_EDIT, PERMS.MOD_TICKETS_EDIT] as const;
|
||||||
|
|
||||||
export const replyHelpCenterTicket = adminAction(
|
export const replyHelpCenterTicket = adminAction(
|
||||||
|
|||||||
@@ -4,17 +4,46 @@ import { revalidatePath } from "next/cache";
|
|||||||
import { requirePermission } from "@/lib/admin/guard";
|
import { requirePermission } from "@/lib/admin/guard";
|
||||||
import { PERMS } from "@/lib/permissions";
|
import { PERMS } from "@/lib/permissions";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { logStaffActivity } from "@/lib/services/staff-activity";
|
||||||
|
|
||||||
export async function deletePhoto(formData: FormData): Promise<void> {
|
export async function deletePhoto(formData: FormData): Promise<void> {
|
||||||
await requirePermission(PERMS.PAGES_EDIT);
|
const staff = await requirePermission(PERMS.PAGES_EDIT);
|
||||||
const id = Number(formData.get("id"));
|
const id = Number(formData.get("id"));
|
||||||
if (!(id > 0)) return;
|
if (!(id > 0)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await prisma.cameraWeb.delete({ where: { id } });
|
await prisma.cameraWeb.delete({ where: { id } });
|
||||||
|
await logStaffActivity({
|
||||||
|
staffId: staff.id,
|
||||||
|
action: "photo_delete",
|
||||||
|
description: `Deleted camera photo #${id}`,
|
||||||
|
targetType: "camera_web",
|
||||||
|
targetId: id,
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// Record may have already been removed; ignore.
|
// Record may have already been removed; ignore.
|
||||||
}
|
}
|
||||||
|
|
||||||
revalidatePath("/admin/photos");
|
revalidatePath("/admin/photos");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function bulkDeletePhotos(formData: FormData): Promise<void> {
|
||||||
|
const staff = await requirePermission(PERMS.PAGES_EDIT);
|
||||||
|
const raw = String(formData.get("ids") ?? "");
|
||||||
|
const ids = raw
|
||||||
|
.split(",")
|
||||||
|
.map((s) => Number(s.trim()))
|
||||||
|
.filter((n) => Number.isFinite(n) && n > 0);
|
||||||
|
if (ids.length === 0) return;
|
||||||
|
|
||||||
|
const result = await prisma.cameraWeb.deleteMany({
|
||||||
|
where: { id: { in: ids } },
|
||||||
|
});
|
||||||
|
await logStaffActivity({
|
||||||
|
staffId: staff.id,
|
||||||
|
action: "photo_bulk_delete",
|
||||||
|
description: `Deleted ${result.count} camera photo(s)`,
|
||||||
|
targetType: "camera_web",
|
||||||
|
});
|
||||||
|
revalidatePath("/admin/photos");
|
||||||
|
}
|
||||||
@@ -181,3 +181,139 @@ export async function bulkGiveBadge({
|
|||||||
data: { given, total: userIds.length, failedIds },
|
data: { given, total: userIds.length, failedIds },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function bulkAdjustCurrency({
|
||||||
|
userIds,
|
||||||
|
amount,
|
||||||
|
type,
|
||||||
|
}: {
|
||||||
|
userIds: number[];
|
||||||
|
/** Positive = give, negative = take. Balances clamped at 0. */
|
||||||
|
amount: number;
|
||||||
|
type: "credits" | "pixels" | "points";
|
||||||
|
}): Promise<
|
||||||
|
ActionResult<{
|
||||||
|
adjusted: number;
|
||||||
|
total: number;
|
||||||
|
failedIds: Array<{ userId: number; reason: string }>;
|
||||||
|
}>
|
||||||
|
> {
|
||||||
|
const staff = await requirePermission(PERMS.USERS_EDIT);
|
||||||
|
if (!Number.isFinite(amount) || amount === 0) {
|
||||||
|
return { ok: false as const, error: "Amount must be a non-zero number" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount > 0) {
|
||||||
|
const given = await bulkGiveCurrency({ userIds, amount, type });
|
||||||
|
if (!given.ok) return given;
|
||||||
|
if (!given.data) {
|
||||||
|
return { ok: false as const, error: "Currency adjustment failed" };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ok: true as const,
|
||||||
|
data: {
|
||||||
|
adjusted: given.data.given,
|
||||||
|
total: given.data.total,
|
||||||
|
failedIds: given.data.failedIds,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const take = Math.abs(Math.trunc(amount));
|
||||||
|
let adjusted = 0;
|
||||||
|
const failedIds: Array<{ userId: number; reason: string }> = [];
|
||||||
|
|
||||||
|
for (const userId of userIds) {
|
||||||
|
try {
|
||||||
|
if (type === "credits") {
|
||||||
|
const user = await prisma.user.findUnique({
|
||||||
|
where: { id: userId },
|
||||||
|
select: { credits: true },
|
||||||
|
});
|
||||||
|
if (!user) {
|
||||||
|
failedIds.push({ userId, reason: "Not found" });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const next = Math.max(0, user.credits - take);
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: userId },
|
||||||
|
data: { credits: next },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const currencyType = type === "pixels" ? 0 : 101;
|
||||||
|
const row = await prisma.usersCurrency.findUnique({
|
||||||
|
where: { userId_type: { userId, type: currencyType } },
|
||||||
|
});
|
||||||
|
const current = row?.amount ?? 0;
|
||||||
|
const next = Math.max(0, current - take);
|
||||||
|
await prisma.usersCurrency.upsert({
|
||||||
|
where: { userId_type: { userId, type: currencyType } },
|
||||||
|
update: { amount: next },
|
||||||
|
create: { userId, type: currencyType, amount: next },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
adjusted++;
|
||||||
|
} catch {
|
||||||
|
failedIds.push({ userId, reason: "Database error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await logStaffActivity({
|
||||||
|
staffId: staff.id,
|
||||||
|
action: "bulk_adjust_currency",
|
||||||
|
description: `Adjusted ${amount} ${type} for ${adjusted} user(s) (DB-only take; no RCON debit)`,
|
||||||
|
targetType: "user",
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
ok: true as const,
|
||||||
|
data: { adjusted, total: userIds.length, failedIds },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persist trade lock on `sanctions.trade_locked_until`.
|
||||||
|
* No first-class RCON trade-lock helper in this CMS — DB only.
|
||||||
|
*/
|
||||||
|
export async function setTradeLock({
|
||||||
|
userId,
|
||||||
|
untilUnix,
|
||||||
|
}: {
|
||||||
|
userId: number;
|
||||||
|
/** Unix seconds; 0 clears the lock. */
|
||||||
|
untilUnix: number;
|
||||||
|
}): Promise<ActionResult<{ userId: number; untilUnix: number }>> {
|
||||||
|
const staff = await requirePermission(PERMS.USERS_EDIT);
|
||||||
|
const until = Math.max(0, Math.trunc(untilUnix));
|
||||||
|
|
||||||
|
const existing = await prisma.sanctions.findFirst({
|
||||||
|
where: { habboId: userId },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
if (existing) {
|
||||||
|
await prisma.sanctions.update({
|
||||||
|
where: { id: existing.id },
|
||||||
|
data: { tradeLockedUntil: until },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await prisma.sanctions.create({
|
||||||
|
data: {
|
||||||
|
habboId: userId,
|
||||||
|
tradeLockedUntil: until,
|
||||||
|
reason: until > 0 ? "Trade lock (CMS)" : "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await logStaffActivity({
|
||||||
|
staffId: staff.id,
|
||||||
|
action: until > 0 ? "trade_lock" : "trade_unlock",
|
||||||
|
description:
|
||||||
|
until > 0
|
||||||
|
? `Trade-locked user #${userId} until ${until}`
|
||||||
|
: `Cleared trade lock for user #${userId}`,
|
||||||
|
targetType: "user",
|
||||||
|
targetId: userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ok: true as const, data: { userId, untilUnix: until } };
|
||||||
|
}
|
||||||
@@ -99,12 +99,61 @@ export async function createTicket(formData: FormData): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!moderated) {
|
if (!moderated) {
|
||||||
|
const banAppeal =
|
||||||
|
String(formData.get("banAppeal") ?? "") === "1" ||
|
||||||
|
String(formData.get("banAppeal") ?? "") === "on";
|
||||||
|
let ticketTitle = title;
|
||||||
|
let categoryId: bigint | null = null;
|
||||||
|
|
||||||
|
if (banAppeal) {
|
||||||
|
if (!/ban\s*appeal/i.test(ticketTitle)) {
|
||||||
|
ticketTitle = `[Ban appeal] ${ticketTitle}`.slice(0, 255);
|
||||||
|
}
|
||||||
|
const existing = await prisma.websiteHelpCenterCategories.findFirst(
|
||||||
|
{
|
||||||
|
where: { name: { equals: "Ban appeal" } },
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (existing) {
|
||||||
|
categoryId = existing.id;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const created = await prisma.websiteHelpCenterCategories.create(
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
name: "Ban appeal",
|
||||||
|
content:
|
||||||
|
"Appeals for account bans. Staff can lift bans from the ticket.",
|
||||||
|
position: 0,
|
||||||
|
},
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
categoryId = created.id;
|
||||||
|
} catch {
|
||||||
|
const again =
|
||||||
|
await prisma.websiteHelpCenterCategories.findFirst({
|
||||||
|
where: { name: { equals: "Ban appeal" } },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
categoryId = again?.id ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const rawCat = String(formData.get("categoryId") ?? "").trim();
|
||||||
|
if (/^\d+$/.test(rawCat)) {
|
||||||
|
categoryId = BigInt(rawCat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
await prisma.websiteHelpCenterTickets.create({
|
await prisma.websiteHelpCenterTickets.create({
|
||||||
data: {
|
data: {
|
||||||
userId,
|
userId,
|
||||||
title,
|
title: ticketTitle,
|
||||||
content,
|
content,
|
||||||
|
categoryId,
|
||||||
open: true,
|
open: true,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export default async function HelpTicketsPage({
|
|||||||
maxLength={5000}
|
maxLength={5000}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<label
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "0.5rem",
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input type="checkbox" name="banAppeal" value="1" />
|
||||||
|
{t("banAppealLabel")}
|
||||||
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<button type="submit" className="btn btn-primary">
|
<button type="submit" className="btn btn-primary">
|
||||||
{t("submit")}
|
{t("submit")}
|
||||||
|
|||||||
+106
-102
@@ -1,6 +1,8 @@
|
|||||||
|
import { Ban } from "lucide-react";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { createBan, liftBan } from "@/actions/admin-bans";
|
import { createBan, liftBan } from "@/actions/admin-bans";
|
||||||
|
import { AdminPageShell } from "@/components/admin/admin-page-shell";
|
||||||
import { StatusCard } from "@/components/admin/dashboard";
|
import { StatusCard } from "@/components/admin/dashboard";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { activeBanWhere, unixNow } from "@/lib/bans";
|
import { activeBanWhere, unixNow } from "@/lib/bans";
|
||||||
@@ -33,112 +35,114 @@ export default async function AdminBans() {
|
|||||||
const accountBans = bans.filter((b) => b.type === "account").length;
|
const accountBans = bans.filter((b) => b.type === "account").length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<AdminPageShell icon={Ban} title={t("title")} subtitle={t("subtitle")}>
|
||||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5 mb-6">
|
<main>
|
||||||
<StatusCard
|
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5 mb-6">
|
||||||
label={t("activeBans")}
|
<StatusCard
|
||||||
value={bans.length}
|
label={t("activeBans")}
|
||||||
state={bans.length > 0 ? "warn" : "ok"}
|
value={bans.length}
|
||||||
icon="🔨"
|
state={bans.length > 0 ? "warn" : "ok"}
|
||||||
/>
|
icon="🔨"
|
||||||
<StatusCard
|
|
||||||
label={t("permanent")}
|
|
||||||
value={permanent}
|
|
||||||
state={permanent > 0 ? "danger" : "neutral"}
|
|
||||||
icon="⛔"
|
|
||||||
/>
|
|
||||||
<StatusCard label={t("accountBans")} value={accountBans} icon="👤" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action={createBan} className="admin-card mb-6">
|
|
||||||
<h3 className="text-sm font-bold text-[var(--admin-text)] m-0 mb-3">
|
|
||||||
{t("newBan")}
|
|
||||||
</h3>
|
|
||||||
<div className="flex gap-2 flex-wrap">
|
|
||||||
<input
|
|
||||||
name="userId"
|
|
||||||
type="number"
|
|
||||||
min={1}
|
|
||||||
placeholder={t("userIdPlaceholder")}
|
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
<select name="type">
|
<StatusCard
|
||||||
<option value="account">{t("typeAccount")}</option>
|
label={t("permanent")}
|
||||||
<option value="ip">{t("typeIp")}</option>
|
value={permanent}
|
||||||
<option value="machine">{t("typeMachine")}</option>
|
state={permanent > 0 ? "danger" : "neutral"}
|
||||||
<option value="super">{t("typeSuper")}</option>
|
icon="⛔"
|
||||||
</select>
|
|
||||||
<input
|
|
||||||
name="hours"
|
|
||||||
type="number"
|
|
||||||
min={0}
|
|
||||||
placeholder={t("hoursPlaceholder")}
|
|
||||||
/>
|
/>
|
||||||
<input
|
<StatusCard label={t("accountBans")} value={accountBans} icon="👤" />
|
||||||
name="reason"
|
|
||||||
placeholder={t("reasonPlaceholder")}
|
|
||||||
className="flex-1 min-w-[160px]"
|
|
||||||
/>
|
|
||||||
<Button type="submit" variant="destructive">
|
|
||||||
{t("ban")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
|
|
||||||
<section className="mt-6">
|
<form action={createBan} className="admin-card mb-6">
|
||||||
<h2 className="admin-section-title">
|
<h3 className="text-sm font-bold text-[var(--admin-text)] m-0 mb-3">
|
||||||
{t("activeBans")} ({bans.length})
|
{t("newBan")}
|
||||||
</h2>
|
</h3>
|
||||||
{bans.length === 0 ? (
|
<div className="flex gap-2 flex-wrap">
|
||||||
<div className="admin-empty">{t("noBans")}</div>
|
<input
|
||||||
) : (
|
name="userId"
|
||||||
<div className="overflow-x-auto">
|
type="number"
|
||||||
<table>
|
min={1}
|
||||||
<thead>
|
placeholder={t("userIdPlaceholder")}
|
||||||
<tr>
|
required
|
||||||
<th>{t("colUserId")}</th>
|
/>
|
||||||
<th>{t("colType")}</th>
|
<select name="type">
|
||||||
<th>{t("colReason")}</th>
|
<option value="account">{t("typeAccount")}</option>
|
||||||
<th>{t("colExpires")}</th>
|
<option value="ip">{t("typeIp")}</option>
|
||||||
<th />
|
<option value="machine">{t("typeMachine")}</option>
|
||||||
</tr>
|
<option value="super">{t("typeSuper")}</option>
|
||||||
</thead>
|
</select>
|
||||||
<tbody>
|
<input
|
||||||
{bans.map((b) => (
|
name="hours"
|
||||||
<tr key={b.id}>
|
type="number"
|
||||||
<td>{b.userId}</td>
|
min={0}
|
||||||
<td>
|
placeholder={t("hoursPlaceholder")}
|
||||||
<span className="inline-block text-[0.72rem] font-bold px-2 py-0.5 rounded-full bg-[var(--admin-accent)]/18 text-[var(--admin-text)]">
|
/>
|
||||||
{b.type}
|
<input
|
||||||
</span>
|
name="reason"
|
||||||
</td>
|
placeholder={t("reasonPlaceholder")}
|
||||||
<td>{b.banReason || "—"}</td>
|
className="flex-1 min-w-[160px]"
|
||||||
<td>
|
/>
|
||||||
{b.banExpire === 0 ? (
|
<Button type="submit" variant="destructive">
|
||||||
<span className="inline-block text-[0.72rem] font-bold px-2 py-0.5 rounded-full bg-[var(--admin-error-subtle)] text-[var(--admin-text)]">
|
{t("ban")}
|
||||||
{t("permanent")}
|
</Button>
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-sm theme-text-muted dark:theme-text-muted whitespace-nowrap">
|
|
||||||
{formatDate(new Date(b.banExpire * 1000))}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<form action={liftBan}>
|
|
||||||
<input type="hidden" name="id" value={b.id} />
|
|
||||||
<Button type="submit" variant="outline">
|
|
||||||
{t("lift")}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</form>
|
||||||
</section>
|
|
||||||
</main>
|
<section className="mt-6">
|
||||||
|
<h2 className="admin-section-title">
|
||||||
|
{t("activeBans")} ({bans.length})
|
||||||
|
</h2>
|
||||||
|
{bans.length === 0 ? (
|
||||||
|
<div className="admin-empty">{t("noBans")}</div>
|
||||||
|
) : (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{t("colUserId")}</th>
|
||||||
|
<th>{t("colType")}</th>
|
||||||
|
<th>{t("colReason")}</th>
|
||||||
|
<th>{t("colExpires")}</th>
|
||||||
|
<th />
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{bans.map((b) => (
|
||||||
|
<tr key={b.id}>
|
||||||
|
<td>{b.userId}</td>
|
||||||
|
<td>
|
||||||
|
<span className="inline-block text-[0.72rem] font-bold px-2 py-0.5 rounded-full bg-[var(--admin-accent)]/18 text-[var(--admin-text)]">
|
||||||
|
{b.type}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{b.banReason || "—"}</td>
|
||||||
|
<td>
|
||||||
|
{b.banExpire === 0 ? (
|
||||||
|
<span className="inline-block text-[0.72rem] font-bold px-2 py-0.5 rounded-full bg-[var(--admin-error-subtle)] text-[var(--admin-text)]">
|
||||||
|
{t("permanent")}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-sm theme-text-muted dark:theme-text-muted whitespace-nowrap">
|
||||||
|
{formatDate(new Date(b.banExpire * 1000))}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<form action={liftBan}>
|
||||||
|
<input type="hidden" name="id" value={b.id} />
|
||||||
|
<Button type="submit" variant="outline">
|
||||||
|
{t("lift")}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</AdminPageShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import { useTranslations } from "next-intl";
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
closeHelpCenterTicket,
|
closeHelpCenterTicket,
|
||||||
|
liftBanFromHelpTicket,
|
||||||
reopenHelpCenterTicket,
|
reopenHelpCenterTicket,
|
||||||
replyHelpCenterTicket,
|
replyHelpCenterTicket,
|
||||||
} from "@/actions/admin-help-tickets";
|
} from "@/actions/admin-help-tickets";
|
||||||
@@ -30,6 +31,7 @@ interface HelpTicketInfo {
|
|||||||
open: boolean;
|
open: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
categoryName?: string | null;
|
||||||
creator: {
|
creator: {
|
||||||
id: number;
|
id: number;
|
||||||
username: string;
|
username: string;
|
||||||
@@ -42,12 +44,17 @@ export function AdminHelpTicketDetail({
|
|||||||
ticket,
|
ticket,
|
||||||
messages: initialMessages,
|
messages: initialMessages,
|
||||||
canEdit,
|
canEdit,
|
||||||
|
canLiftBan = false,
|
||||||
|
hasActiveBan = false,
|
||||||
listHref = "/admin/help-tickets",
|
listHref = "/admin/help-tickets",
|
||||||
hideRequesterContact = false,
|
hideRequesterContact = false,
|
||||||
}: {
|
}: {
|
||||||
ticket: HelpTicketInfo;
|
ticket: HelpTicketInfo;
|
||||||
messages: ThreadMessage[];
|
messages: ThreadMessage[];
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
|
/** Staff may lift requester bans (USERS_BAN). */
|
||||||
|
canLiftBan?: boolean;
|
||||||
|
hasActiveBan?: boolean;
|
||||||
listHref?: string;
|
listHref?: string;
|
||||||
/** Hide email/IP-style contact for mod-lite surfaces. */
|
/** Hide email/IP-style contact for mod-lite surfaces. */
|
||||||
hideRequesterContact?: boolean;
|
hideRequesterContact?: boolean;
|
||||||
@@ -94,6 +101,13 @@ export function AdminHelpTicketDetail({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleLiftBan() {
|
||||||
|
if (!ticket.creator || isPending) return;
|
||||||
|
run(() => liftBanFromHelpTicket({ ticketId: ticket.id }), {
|
||||||
|
successMessage: t("success.banLifted"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
@@ -110,6 +124,12 @@ export function AdminHelpTicketDetail({
|
|||||||
<Badge variant={ticket.open ? "default" : "secondary"}>
|
<Badge variant={ticket.open ? "default" : "secondary"}>
|
||||||
{ticket.open ? t("statusOpen") : t("statusClosed")}
|
{ticket.open ? t("statusOpen") : t("statusClosed")}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
{ticket.categoryName ? (
|
||||||
|
<Badge variant="outline">{ticket.categoryName}</Badge>
|
||||||
|
) : null}
|
||||||
|
{hasActiveBan ? (
|
||||||
|
<Badge variant="destructive">{t("requesterBanned")}</Badge>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold">{ticket.title}</h1>
|
<h1 className="text-2xl font-bold">{ticket.title}</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,13 +228,24 @@ export function AdminHelpTicketDetail({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{canEdit && (
|
{(canEdit || (canLiftBan && hasActiveBan)) && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="pb-2">
|
<CardHeader className="pb-2">
|
||||||
<CardTitle className="text-sm">{t("actionsTitle")}</CardTitle>
|
<CardTitle className="text-sm">{t("actionsTitle")}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-2">
|
<CardContent className="space-y-2">
|
||||||
{ticket.open ? (
|
{canLiftBan && hasActiveBan && ticket.creator ? (
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
className="w-full"
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={handleLiftBan}
|
||||||
|
>
|
||||||
|
{t("liftBanSubmit")}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
{canEdit && ticket.open ? (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -224,7 +255,8 @@ export function AdminHelpTicketDetail({
|
|||||||
>
|
>
|
||||||
{t("closeSubmit")}
|
{t("closeSubmit")}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : null}
|
||||||
|
{canEdit && !ticket.open ? (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -234,7 +266,7 @@ export function AdminHelpTicketDetail({
|
|||||||
>
|
>
|
||||||
{t("reopenSubmit")}
|
{t("reopenSubmit")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
) : null}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { getTranslations } from "next-intl/server";
|
|||||||
import { TicketQueueBanner } from "@/components/admin/ticket-queue-banner";
|
import { TicketQueueBanner } from "@/components/admin/ticket-queue-banner";
|
||||||
import { getMinStaffRank } from "@/lib/admin/min-staff-rank";
|
import { getMinStaffRank } from "@/lib/admin/min-staff-rank";
|
||||||
import { positiveBigInt } from "@/lib/api";
|
import { positiveBigInt } from "@/lib/api";
|
||||||
|
import { activeBanWhere } from "@/lib/bans";
|
||||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { AdminHelpTicketDetail } from "./admin-help-ticket-detail";
|
import { AdminHelpTicketDetail } from "./admin-help-ticket-detail";
|
||||||
@@ -29,6 +30,7 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
|
categoryId: true,
|
||||||
title: true,
|
title: true,
|
||||||
content: true,
|
content: true,
|
||||||
open: true,
|
open: true,
|
||||||
@@ -57,9 +59,9 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
const users =
|
const [users, category, activeBan] = await Promise.all([
|
||||||
authorIds.length > 0
|
authorIds.length > 0
|
||||||
? await prisma.user.findMany({
|
? prisma.user.findMany({
|
||||||
where: { id: { in: authorIds } },
|
where: { id: { in: authorIds } },
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -68,7 +70,20 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
mail: true,
|
mail: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: [];
|
: Promise.resolve([]),
|
||||||
|
ticket.categoryId != null
|
||||||
|
? prisma.websiteHelpCenterCategories.findUnique({
|
||||||
|
where: { id: ticket.categoryId },
|
||||||
|
select: { name: true },
|
||||||
|
})
|
||||||
|
: Promise.resolve(null),
|
||||||
|
ticket.userId != null
|
||||||
|
? prisma.ban.findFirst({
|
||||||
|
where: { userId: ticket.userId, ...activeBanWhere() },
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
: Promise.resolve(null),
|
||||||
|
]);
|
||||||
|
|
||||||
const userById = new Map(users.map((u) => [u.id, u]));
|
const userById = new Map(users.map((u) => [u.id, u]));
|
||||||
const openerId = ticket.userId;
|
const openerId = ticket.userId;
|
||||||
@@ -104,6 +119,10 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
const creator = openerId != null ? userById.get(openerId) : undefined;
|
const creator = openerId != null ? userById.get(openerId) : undefined;
|
||||||
|
|
||||||
const canEdit = canAccess(permissions, PERMS.TICKETS_EDIT, session.user.rank);
|
const canEdit = canAccess(permissions, PERMS.TICKETS_EDIT, session.user.rank);
|
||||||
|
const canLiftBan = canAccess(permissions, PERMS.USERS_BAN, session.user.rank);
|
||||||
|
const isBanAppeal =
|
||||||
|
/ban\s*appeal/i.test(ticket.title) ||
|
||||||
|
/ban\s*appeal/i.test(category?.name ?? "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@@ -119,6 +138,7 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
open: ticket.open,
|
open: ticket.open,
|
||||||
createdAt: (ticket.createdAt ?? new Date()).toISOString(),
|
createdAt: (ticket.createdAt ?? new Date()).toISOString(),
|
||||||
updatedAt: (ticket.updatedAt ?? new Date()).toISOString(),
|
updatedAt: (ticket.updatedAt ?? new Date()).toISOString(),
|
||||||
|
categoryName: category?.name ?? (isBanAppeal ? "Ban appeal" : null),
|
||||||
creator: creator
|
creator: creator
|
||||||
? {
|
? {
|
||||||
id: creator.id,
|
id: creator.id,
|
||||||
@@ -130,6 +150,8 @@ export default async function AdminHelpTicketDetailPage({
|
|||||||
}}
|
}}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
canEdit={canEdit}
|
canEdit={canEdit}
|
||||||
|
canLiftBan={canLiftBan}
|
||||||
|
hasActiveBan={!!activeBan}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+106
-52
@@ -1,35 +1,62 @@
|
|||||||
|
import { Camera } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { deletePhoto } from "@/actions/admin-photos";
|
import { deletePhoto } from "@/actions/admin-photos";
|
||||||
|
import { AdminPageShell } from "@/components/admin/admin-page-shell";
|
||||||
import { StatusCard } from "@/components/admin/dashboard";
|
import { StatusCard } from "@/components/admin/dashboard";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
|
||||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export default async function AdminPhotos() {
|
export default async function AdminPhotos({
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
searchParams: Promise<Record<string, string>>;
|
||||||
|
}) {
|
||||||
const { session, permissions } = await getAdminContext();
|
const { session, permissions } = await getAdminContext();
|
||||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||||
redirect("/admin");
|
redirect("/admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
const t = await getTranslations("pages.admin.photos");
|
const t = await getTranslations("pages.admin.photos");
|
||||||
|
const parsed = parseListParams(new URLSearchParams(await searchParams));
|
||||||
|
|
||||||
|
const total = await prisma.cameraWeb.count().catch(() => 0);
|
||||||
|
const pagination = calcPagination(total, parsed.page, parsed.perPage || 24);
|
||||||
|
|
||||||
let photos: Awaited<ReturnType<typeof prisma.cameraWeb.findMany>> = [];
|
let photos: Awaited<ReturnType<typeof prisma.cameraWeb.findMany>> = [];
|
||||||
try {
|
try {
|
||||||
photos = await prisma.cameraWeb.findMany({
|
photos = await prisma.cameraWeb.findMany({
|
||||||
orderBy: { timestamp: "desc" },
|
orderBy: { timestamp: "desc" },
|
||||||
take: 60,
|
skip: pagination.offset,
|
||||||
|
take: pagination.perPage,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
photos = [];
|
photos = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userIds = [...new Set(photos.map((p) => p.userId))];
|
||||||
|
const users =
|
||||||
|
userIds.length > 0
|
||||||
|
? await prisma.user
|
||||||
|
.findMany({
|
||||||
|
where: { id: { in: userIds } },
|
||||||
|
select: { id: true, username: true },
|
||||||
|
})
|
||||||
|
.catch(() => [])
|
||||||
|
: [];
|
||||||
|
const usernameById = new Map(users.map((u) => [u.id, u.username]));
|
||||||
|
|
||||||
const uniqueRooms = new Set(photos.map((p) => p.roomId)).size;
|
const uniqueRooms = new Set(photos.map((p) => p.roomId)).size;
|
||||||
const uniqueUsers = new Set(photos.map((p) => p.userId)).size;
|
const uniqueUsers = new Set(photos.map((p) => p.userId)).size;
|
||||||
|
const canEdit = canAccess(permissions, PERMS.PAGES_EDIT, session.user.rank);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<AdminPageShell icon={Camera} title={t("title")} subtitle={t("subtitle")}>
|
||||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5 mb-6">
|
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5 mb-6">
|
||||||
<StatusCard label={t("photosShown")} value={photos.length} icon="📸" />
|
<StatusCard label={t("photosShown")} value={photos.length} icon="📸" />
|
||||||
<StatusCard
|
<StatusCard
|
||||||
@@ -44,68 +71,95 @@ export default async function AdminPhotos() {
|
|||||||
hint={t("distinctPhotographers")}
|
hint={t("distinctPhotographers")}
|
||||||
icon="👤"
|
icon="👤"
|
||||||
/>
|
/>
|
||||||
|
<StatusCard label={t("total")} value={total} icon="🗂" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="mt-6">
|
<section className="mt-2">
|
||||||
<h2 className="admin-section-title">{t("recentPhotos")}</h2>
|
<h2 className="admin-section-title">{t("recentPhotos")}</h2>
|
||||||
{photos.length === 0 ? (
|
{photos.length === 0 ? (
|
||||||
<div className="admin-empty">{t("noPhotos")}</div>
|
<div className="admin-empty">{t("noPhotos")}</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||||
{photos.map((p) => (
|
{photos.map((p) => {
|
||||||
<div
|
const username = usernameById.get(p.userId) ?? `#${p.userId}`;
|
||||||
key={String(p.id)}
|
return (
|
||||||
className="admin-card"
|
<div
|
||||||
style={{ padding: 0, overflow: "hidden" }}
|
key={String(p.id)}
|
||||||
>
|
className="admin-card"
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
style={{ padding: 0, overflow: "hidden" }}
|
||||||
<img
|
>
|
||||||
src={p.url}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
alt={t("photoAlt", { id: String(p.id) })}
|
<img
|
||||||
style={{
|
src={p.url}
|
||||||
width: "100%",
|
alt={t("photoAlt", { id: String(p.id) })}
|
||||||
height: 200,
|
|
||||||
objectFit: "cover",
|
|
||||||
display: "block",
|
|
||||||
background: "#f1f5f9",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style={{ padding: "0.85rem 1.05rem 1.05rem" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
width: "100%",
|
||||||
justifyContent: "space-between",
|
height: 200,
|
||||||
gap: "0.5rem",
|
objectFit: "cover",
|
||||||
alignItems: "baseline",
|
display: "block",
|
||||||
|
background: "#f1f5f9",
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<strong>#{String(p.id)}</strong>
|
<div style={{ padding: "0.85rem 1.05rem 1.05rem" }}>
|
||||||
<span className="text-sm theme-text-muted dark:theme-text-muted">
|
<div
|
||||||
{t("colRoom")} {p.roomId}
|
style={{
|
||||||
</span>
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
gap: "0.5rem",
|
||||||
|
alignItems: "baseline",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<strong>#{String(p.id)}</strong>
|
||||||
|
<Link
|
||||||
|
href={`/admin/rooms/edit/${p.roomId}`}
|
||||||
|
className="text-sm theme-text-muted dark:theme-text-muted hover:underline"
|
||||||
|
>
|
||||||
|
{t("colRoom")} {p.roomId}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
className="text-xs theme-text-muted dark:theme-text-muted"
|
||||||
|
style={{ margin: "0.3rem 0 0" }}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`/admin/users/show/${p.userId}`}
|
||||||
|
className="hover:underline"
|
||||||
|
>
|
||||||
|
{t("byUser", { username })}
|
||||||
|
</Link>{" "}
|
||||||
|
·{" "}
|
||||||
|
{new Date(p.timestamp * 1000)
|
||||||
|
.toISOString()
|
||||||
|
.slice(0, 16)
|
||||||
|
.replace("T", " ")}
|
||||||
|
</p>
|
||||||
|
{canEdit ? (
|
||||||
|
<form
|
||||||
|
action={deletePhoto}
|
||||||
|
style={{ marginTop: "0.75rem" }}
|
||||||
|
>
|
||||||
|
<input type="hidden" name="id" value={String(p.id)} />
|
||||||
|
<Button type="submit" variant="destructive">
|
||||||
|
{t("delete")}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<p
|
|
||||||
className="text-xs theme-text-muted dark:theme-text-muted"
|
|
||||||
style={{ margin: "0.3rem 0 0" }}
|
|
||||||
>
|
|
||||||
{t("colUser")} {p.userId} ·{" "}
|
|
||||||
{new Date(p.timestamp * 1000)
|
|
||||||
.toISOString()
|
|
||||||
.slice(0, 16)
|
|
||||||
.replace("T", " ")}
|
|
||||||
</p>
|
|
||||||
<form action={deletePhoto} style={{ marginTop: "0.75rem" }}>
|
|
||||||
<input type="hidden" name="id" value={String(p.id)} />
|
|
||||||
<Button type="submit" variant="destructive">
|
|
||||||
{t("delete")}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
))}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{pagination.lastPage > 1 ? (
|
||||||
|
<p className="text-sm text-muted-foreground mt-4">
|
||||||
|
{t("pageOf", {
|
||||||
|
page: pagination.page,
|
||||||
|
last: pagination.lastPage,
|
||||||
|
total,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</AdminPageShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
VolumeX,
|
VolumeX,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { setTradeLock } from "@/actions/bulk-users";
|
||||||
import {
|
import {
|
||||||
alertUser,
|
alertUser,
|
||||||
disconnectUser,
|
disconnectUser,
|
||||||
@@ -234,6 +235,40 @@ export function UserQuickActions({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Trade lock (DB only — no RCON helper) */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="text-xs text-muted-foreground">
|
||||||
|
Trade lock (CMS DB)
|
||||||
|
</Label>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={() => {
|
||||||
|
const until = Math.floor(Date.now() / 1000) + 7 * 24 * 3600;
|
||||||
|
run(() => setTradeLock({ userId, untilUnix: until }), {
|
||||||
|
successMessage: `${username} trade-locked for 7 days.`,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Lock 7d
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={() => {
|
||||||
|
run(() => setTradeLock({ userId, untilUnix: 0 }), {
|
||||||
|
successMessage: `${username} trade lock cleared.`,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clear lock
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { Users } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
|
import { AdminPageShell } from "@/components/admin/admin-page-shell";
|
||||||
import { fetchAdminList } from "@/lib/admin-list";
|
import { fetchAdminList } from "@/lib/admin-list";
|
||||||
import { canAccess, PERMS } from "@/lib/permissions";
|
import { canAccess, PERMS } from "@/lib/permissions";
|
||||||
import { CreateUserDialog } from "./_components/create-user-dialog";
|
import { CreateUserDialog } from "./_components/create-user-dialog";
|
||||||
@@ -43,17 +46,22 @@ export default async function UsersPage({
|
|||||||
searchParams,
|
searchParams,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const t = await getTranslations("pages.admin.users");
|
||||||
const canEdit = canAccess(result.permissions, PERMS.USERS_EDIT, result.rank);
|
const canEdit = canAccess(result.permissions, PERMS.USERS_EDIT, result.rank);
|
||||||
const canBan = canAccess(result.permissions, PERMS.USERS_BAN, result.rank);
|
const canBan = canAccess(result.permissions, PERMS.USERS_BAN, result.rank);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<AdminPageShell
|
||||||
<div className="flex items-center justify-between">
|
icon={Users}
|
||||||
<p className="text-muted-foreground">
|
title={t("title")}
|
||||||
{result.total.toLocaleString()} users total
|
subtitle={t("subtitle")}
|
||||||
</p>
|
actions={
|
||||||
{canEdit && <CreateUserDialog sessionRank={result.rank} />}
|
canEdit ? <CreateUserDialog sessionRank={result.rank} /> : undefined
|
||||||
</div>
|
}
|
||||||
|
>
|
||||||
|
<p className="text-muted-foreground m-0">
|
||||||
|
{result.total.toLocaleString()} users total
|
||||||
|
</p>
|
||||||
|
|
||||||
<UsersTable
|
<UsersTable
|
||||||
data={{
|
data={{
|
||||||
@@ -66,6 +74,6 @@ export default async function UsersPage({
|
|||||||
canEdit={canEdit}
|
canEdit={canEdit}
|
||||||
canBan={canBan}
|
canBan={canBan}
|
||||||
/>
|
/>
|
||||||
</div>
|
</AdminPageShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||||
import { getWatchedUserIds } from "@/lib/services/watch";
|
import { getWatchedUserIds } from "@/lib/services/watch";
|
||||||
@@ -23,6 +24,7 @@ export default async function UserShowPage({
|
|||||||
redirect("/admin");
|
redirect("/admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const t = await getTranslations("pages.admin.users.detail");
|
||||||
const canEdit = canAccess(permissions, PERMS.USERS_EDIT, session.user.rank);
|
const canEdit = canAccess(permissions, PERMS.USERS_EDIT, session.user.rank);
|
||||||
const data = await loadUserById(id);
|
const data = await loadUserById(id);
|
||||||
const sanctions = await loadUserSanctions(data.user.id);
|
const sanctions = await loadUserSanctions(data.user.id);
|
||||||
@@ -53,15 +55,17 @@ export default async function UserShowPage({
|
|||||||
>
|
>
|
||||||
<Tabs defaultValue="info" className="space-y-4 min-w-0">
|
<Tabs defaultValue="info" className="space-y-4 min-w-0">
|
||||||
<TabsList>
|
<TabsList>
|
||||||
<TabsTrigger value="info">Account Info</TabsTrigger>
|
<TabsTrigger value="info">{t("tabInfo")}</TabsTrigger>
|
||||||
<TabsTrigger value="badges">
|
<TabsTrigger value="badges">
|
||||||
Badges ({data.user.badges.length})
|
{t("tabBadges", { count: data.user.badges.length })}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="rooms">
|
||||||
|
{t("tabRooms", { count: data.roomCount })}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="rooms">Rooms ({data.roomCount})</TabsTrigger>
|
|
||||||
<TabsTrigger value="sanctions">
|
<TabsTrigger value="sanctions">
|
||||||
Sanctions ({sanctions.events.length})
|
{t("tabSanctions", { count: sanctions.events.length })}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="activity">Activity</TabsTrigger>
|
<TabsTrigger value="activity">{t("tabActivity")}</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="info">
|
<TabsContent value="info">
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import Link from "next/link";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import {
|
import {
|
||||||
|
bulkAdjustCurrency,
|
||||||
bulkBan,
|
bulkBan,
|
||||||
bulkGiveBadge,
|
bulkGiveBadge,
|
||||||
bulkGiveCurrency,
|
|
||||||
bulkUnban,
|
bulkUnban,
|
||||||
} from "@/actions/bulk-users";
|
} from "@/actions/bulk-users";
|
||||||
import { DataTable } from "@/components/admin/data-table";
|
import { DataTable } from "@/components/admin/data-table";
|
||||||
@@ -283,20 +283,20 @@ export function UsersTable({ data, canEdit, canBan }: UsersTableProps) {
|
|||||||
if (pending?.kind !== "give-currency") return;
|
if (pending?.kind !== "give-currency") return;
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
const result = await bulkGiveCurrency({
|
const result = await bulkAdjustCurrency({
|
||||||
userIds: pending.ids,
|
userIds: pending.ids,
|
||||||
amount: Number(currencyAmount),
|
amount: Number(currencyAmount),
|
||||||
type: currencyType,
|
type: currencyType,
|
||||||
});
|
});
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
const data = result.data as {
|
const data = result.data as {
|
||||||
given: number;
|
adjusted: number;
|
||||||
total: number;
|
total: number;
|
||||||
failedIds: { userId: number; reason: string }[];
|
failedIds: { userId: number; reason: string }[];
|
||||||
};
|
};
|
||||||
reportResult(
|
reportResult(
|
||||||
`Given ${currencyAmount} ${currencyType}`,
|
`Adjusted ${currencyAmount} ${currencyType}`,
|
||||||
data.given,
|
data.adjusted,
|
||||||
data.total,
|
data.total,
|
||||||
data.failedIds.length,
|
data.failedIds.length,
|
||||||
);
|
);
|
||||||
@@ -344,7 +344,7 @@ export function UsersTable({ data, canEdit, canBan }: UsersTableProps) {
|
|||||||
bulkActions.push({ label: "Unban", value: "unban" });
|
bulkActions.push({ label: "Unban", value: "unban" });
|
||||||
}
|
}
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
bulkActions.push({ label: "Give credits", value: "give-currency" });
|
bulkActions.push({ label: "Adjust currency", value: "give-currency" });
|
||||||
bulkActions.push({ label: "Give badge", value: "give-badge" });
|
bulkActions.push({ label: "Give badge", value: "give-badge" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +424,7 @@ export function UsersTable({ data, canEdit, canBan }: UsersTableProps) {
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
Give currency to{" "}
|
Adjust currency for{" "}
|
||||||
{pending?.kind === "give-currency" ? pending.ids.length : 0} users
|
{pending?.kind === "give-currency" ? pending.ids.length : 0} users
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
@@ -459,7 +459,9 @@ export function UsersTable({ data, canEdit, canBan }: UsersTableProps) {
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="give-amount">Amount</Label>
|
<Label htmlFor="give-amount">
|
||||||
|
Amount (positive = give, negative = take)
|
||||||
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="give-amount"
|
id="give-amount"
|
||||||
type="number"
|
type="number"
|
||||||
@@ -478,9 +480,9 @@ export function UsersTable({ data, canEdit, canBan }: UsersTableProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={confirmGiveCurrency}
|
onClick={confirmGiveCurrency}
|
||||||
disabled={busy || !currencyAmount}
|
disabled={busy || !currencyAmount || Number(currencyAmount) === 0}
|
||||||
>
|
>
|
||||||
Give
|
Apply
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import { existsSync, readFileSync } from "node:fs";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("staff smoke contract", () => {
|
||||||
|
it("gates photos delete/bulk with PAGES_EDIT", () => {
|
||||||
|
const src = readFileSync("src/actions/admin-photos.ts", "utf8");
|
||||||
|
expect(src).toContain("PERMS.PAGES_EDIT");
|
||||||
|
expect(src).toContain("deletePhoto");
|
||||||
|
expect(src).toContain("bulkDeletePhotos");
|
||||||
|
expect(src).toContain("logStaffActivity");
|
||||||
|
expect(existsSync("src/app/admin/photos/page.tsx")).toBe(true);
|
||||||
|
expect(readFileSync("src/app/admin/photos/page.tsx", "utf8")).toContain(
|
||||||
|
"AdminPageShell",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gates bans create/lift", () => {
|
||||||
|
expect(existsSync("src/app/admin/bans/page.tsx")).toBe(true);
|
||||||
|
const bans = readFileSync("src/actions/admin-bans.ts", "utf8");
|
||||||
|
expect(bans).toContain("liftBan");
|
||||||
|
expect(bans).toContain("createBan");
|
||||||
|
expect(readFileSync("src/app/admin/bans/page.tsx", "utf8")).toContain(
|
||||||
|
"AdminPageShell",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("wires ban appeal lift on help tickets", () => {
|
||||||
|
const actions = readFileSync("src/actions/admin-help-tickets.ts", "utf8");
|
||||||
|
expect(actions).toContain("liftBanFromHelpTicket");
|
||||||
|
expect(actions).toContain("PERMS.USERS_BAN");
|
||||||
|
const detail = readFileSync(
|
||||||
|
"src/app/admin/help-tickets/[id]/admin-help-ticket-detail.tsx",
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
expect(detail).toContain("liftBanFromHelpTicket");
|
||||||
|
expect(detail).toContain("canLiftBan");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exposes sanction timeline on user show", () => {
|
||||||
|
expect(
|
||||||
|
existsSync("src/app/admin/users/_components/user-sanction-timeline.tsx"),
|
||||||
|
).toBe(true);
|
||||||
|
expect(existsSync("src/app/admin/users/_lib/load-user-sanctions.ts")).toBe(
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
readFileSync("src/app/admin/users/show/[id]/page.tsx", "utf8"),
|
||||||
|
).toContain("UserSanctionTimeline");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ships shared ops + ticket queue helpers", () => {
|
||||||
|
expect(existsSync("src/lib/admin/ops-health.ts")).toBe(true);
|
||||||
|
expect(existsSync("src/lib/admin/ticket-queue-counts.ts")).toBe(true);
|
||||||
|
expect(existsSync("src/lib/admin/ops-online-users.ts")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("caches analytics via redisCache", () => {
|
||||||
|
for (const path of [
|
||||||
|
"src/app/admin/analytics/page.tsx",
|
||||||
|
"src/app/admin/analytics/activity/page.tsx",
|
||||||
|
"src/app/admin/analytics/economy/page.tsx",
|
||||||
|
]) {
|
||||||
|
expect(readFileSync(path, "utf8"), path).toContain("redisCache");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exports bulk adjust currency and trade lock", () => {
|
||||||
|
const src = readFileSync("src/actions/bulk-users.ts", "utf8");
|
||||||
|
expect(src).toContain("bulkAdjustCurrency");
|
||||||
|
expect(src).toContain("setTradeLock");
|
||||||
|
expect(src).toContain("tradeLockedUntil");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("guards dual ticket queues on admin and mod", () => {
|
||||||
|
for (const path of [
|
||||||
|
"src/app/admin/tickets/page.tsx",
|
||||||
|
"src/app/admin/help-tickets/page.tsx",
|
||||||
|
"src/app/mod/tickets/page.tsx",
|
||||||
|
"src/app/mod/help-tickets/page.tsx",
|
||||||
|
]) {
|
||||||
|
expect(existsSync(path), path).toBe(true);
|
||||||
|
expect(readFileSync(path, "utf8"), path).toContain("TicketQueueBanner");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Кандидатствайте за персонал на {hotel}",
|
"title": "Кандидатствайте за персонал на {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Времево клеймо",
|
"colTimestamp": "Времево клеймо",
|
||||||
"colActions": "Действия",
|
"colActions": "Действия",
|
||||||
"photoAlt": "Снимка на потребител #{id}",
|
"photoAlt": "Снимка на потребител #{id}",
|
||||||
"byUser": "от {username}"
|
"byUser": "от {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Потребители",
|
"title": "Потребители",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Бан потребител",
|
"banUser": "Бан потребител",
|
||||||
"resetPassword": "Нулирайте паролата",
|
"resetPassword": "Нулирайте паролата",
|
||||||
"deleteUser": "Изтриване на потребител",
|
"deleteUser": "Изтриване на потребител",
|
||||||
"confirmDelete": "Сигурни ли сте, че искате да изтриете {username}? Това не може да бъде отменено."
|
"confirmDelete": "Сигурни ли сте, че искате да изтриете {username}? Това не може да бъде отменено.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Редактиране на потребител: {username}",
|
"title": "Редактиране на потребител: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Požádejte o zaměstnance {hotel}",
|
"title": "Požádejte o zaměstnance {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Časové razítko",
|
"colTimestamp": "Časové razítko",
|
||||||
"colActions": "Akce",
|
"colActions": "Akce",
|
||||||
"photoAlt": "Uživatelská fotka č. {id}",
|
"photoAlt": "Uživatelská fotka č. {id}",
|
||||||
"byUser": "od {username}"
|
"byUser": "od {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Uživatelé",
|
"title": "Uživatelé",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Zakázat uživatele",
|
"banUser": "Zakázat uživatele",
|
||||||
"resetPassword": "Obnovit heslo",
|
"resetPassword": "Obnovit heslo",
|
||||||
"deleteUser": "Smazat uživatele",
|
"deleteUser": "Smazat uživatele",
|
||||||
"confirmDelete": "Opravdu chcete smazat uživatele {username}? Toto nelze vrátit zpět."
|
"confirmDelete": "Opravdu chcete smazat uživatele {username}? Toto nelze vrátit zpět.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Upravit uživatele: {username}",
|
"title": "Upravit uživatele: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Ansøg om {hotel} personale",
|
"title": "Ansøg om {hotel} personale",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Tidsstempel",
|
"colTimestamp": "Tidsstempel",
|
||||||
"colActions": "Handlinger",
|
"colActions": "Handlinger",
|
||||||
"photoAlt": "User photo #{id}",
|
"photoAlt": "User photo #{id}",
|
||||||
"byUser": "by {username}"
|
"byUser": "by {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Brugere",
|
"title": "Brugere",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Forbyd bruger",
|
"banUser": "Forbyd bruger",
|
||||||
"resetPassword": "Nulstil adgangskode",
|
"resetPassword": "Nulstil adgangskode",
|
||||||
"deleteUser": "Slet bruger",
|
"deleteUser": "Slet bruger",
|
||||||
"confirmDelete": "Er du sikker på, at du vil slette {username}? Dette kan ikke fortrydes."
|
"confirmDelete": "Er du sikker på, at du vil slette {username}? Dette kan ikke fortrydes.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Rediger bruger: {username}",
|
"title": "Rediger bruger: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Bewirb dich als {hotel} Team",
|
"title": "Bewirb dich als {hotel} Team",
|
||||||
@@ -1081,7 +1082,15 @@
|
|||||||
"colTimestamp": "Zeitstempel",
|
"colTimestamp": "Zeitstempel",
|
||||||
"colActions": "Aktionen",
|
"colActions": "Aktionen",
|
||||||
"photoAlt": "Benutzerfoto #{id}",
|
"photoAlt": "Benutzerfoto #{id}",
|
||||||
"byUser": "von {username}"
|
"byUser": "von {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Benutzer",
|
"title": "Benutzer",
|
||||||
@@ -1128,7 +1137,12 @@
|
|||||||
"banUser": "Benutzer bannen",
|
"banUser": "Benutzer bannen",
|
||||||
"resetPassword": "Passwort zurücksetzen",
|
"resetPassword": "Passwort zurücksetzen",
|
||||||
"deleteUser": "Benutzer löschen",
|
"deleteUser": "Benutzer löschen",
|
||||||
"confirmDelete": "Bist du sicher, dass du {username} löschen möchtest? Dies kann nicht rückgängig gemacht werden."
|
"confirmDelete": "Bist du sicher, dass du {username} löschen möchtest? Dies kann nicht rückgängig gemacht werden.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Benutzer bearbeiten: {username}",
|
"title": "Benutzer bearbeiten: {username}",
|
||||||
@@ -2695,11 +2709,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Κάντε αίτηση για προσωπικό {hotel}",
|
"title": "Κάντε αίτηση για προσωπικό {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Χρονική σήμανση",
|
"colTimestamp": "Χρονική σήμανση",
|
||||||
"colActions": "Δράσεις",
|
"colActions": "Δράσεις",
|
||||||
"photoAlt": "Φωτογραφία χρήστη #{id}",
|
"photoAlt": "Φωτογραφία χρήστη #{id}",
|
||||||
"byUser": "από {username}"
|
"byUser": "από {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Χρήστες",
|
"title": "Χρήστες",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Απαγόρευση χρήστη",
|
"banUser": "Απαγόρευση χρήστη",
|
||||||
"resetPassword": "Επαναφορά κωδικού πρόσβασης",
|
"resetPassword": "Επαναφορά κωδικού πρόσβασης",
|
||||||
"deleteUser": "Διαγραφή χρήστη",
|
"deleteUser": "Διαγραφή χρήστη",
|
||||||
"confirmDelete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το {username}; Αυτό δεν μπορεί να αναιρεθεί."
|
"confirmDelete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το {username}; Αυτό δεν μπορεί να αναιρεθεί.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Επεξεργασία χρήστη: {username}",
|
"title": "Επεξεργασία χρήστη: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+19
-2
@@ -539,6 +539,7 @@
|
|||||||
"subjectPlaceholder": "Subject",
|
"subjectPlaceholder": "Subject",
|
||||||
"contentPlaceholder": "Describe your issue…",
|
"contentPlaceholder": "Describe your issue…",
|
||||||
"submit": "Submit ticket",
|
"submit": "Submit ticket",
|
||||||
|
"banAppealLabel": "This is a ban appeal",
|
||||||
"listTitle": "Your tickets",
|
"listTitle": "Your tickets",
|
||||||
"listSubtitle": "Every request you have sent to staff",
|
"listSubtitle": "Every request you have sent to staff",
|
||||||
"listEmpty": "You have no tickets yet.",
|
"listEmpty": "You have no tickets yet.",
|
||||||
@@ -1359,7 +1360,15 @@
|
|||||||
"colTimestamp": "Timestamp",
|
"colTimestamp": "Timestamp",
|
||||||
"colActions": "Actions",
|
"colActions": "Actions",
|
||||||
"photoAlt": "User photo #{id}",
|
"photoAlt": "User photo #{id}",
|
||||||
"byUser": "by {username}"
|
"byUser": "by {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Users",
|
"title": "Users",
|
||||||
@@ -1386,6 +1395,11 @@
|
|||||||
"detail": {
|
"detail": {
|
||||||
"title": "User: {username}",
|
"title": "User: {username}",
|
||||||
"subtitle": "Account details and management",
|
"subtitle": "Account details and management",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity",
|
||||||
"overview": "Overview",
|
"overview": "Overview",
|
||||||
"actions": "Actions",
|
"actions": "Actions",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
@@ -1537,6 +1551,8 @@
|
|||||||
"replyHint": "Ctrl+Enter to send.",
|
"replyHint": "Ctrl+Enter to send.",
|
||||||
"closeSubmit": "Close ticket",
|
"closeSubmit": "Close ticket",
|
||||||
"reopenSubmit": "Reopen ticket",
|
"reopenSubmit": "Reopen ticket",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned",
|
||||||
"closedHint": "This ticket is closed.",
|
"closedHint": "This ticket is closed.",
|
||||||
"actionsTitle": "Actions",
|
"actionsTitle": "Actions",
|
||||||
"requesterTitle": "Requester",
|
"requesterTitle": "Requester",
|
||||||
@@ -1546,7 +1562,8 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cfh": {
|
"cfh": {
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Solicitar unirte al equipo de {hotel}",
|
"title": "Solicitar unirte al equipo de {hotel}",
|
||||||
@@ -1081,7 +1082,15 @@
|
|||||||
"colTimestamp": "Fecha",
|
"colTimestamp": "Fecha",
|
||||||
"colActions": "Acciones",
|
"colActions": "Acciones",
|
||||||
"photoAlt": "Foto de usuario #{id}",
|
"photoAlt": "Foto de usuario #{id}",
|
||||||
"byUser": "por {username}"
|
"byUser": "por {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Usuarios",
|
"title": "Usuarios",
|
||||||
@@ -1128,7 +1137,12 @@
|
|||||||
"banUser": "Sancionar usuario",
|
"banUser": "Sancionar usuario",
|
||||||
"resetPassword": "Restablecer contraseña",
|
"resetPassword": "Restablecer contraseña",
|
||||||
"deleteUser": "Eliminar usuario",
|
"deleteUser": "Eliminar usuario",
|
||||||
"confirmDelete": "¿Estás seguro de que quieres eliminar a {username}? Esto no se puede deshacer."
|
"confirmDelete": "¿Estás seguro de que quieres eliminar a {username}? Esto no se puede deshacer.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Editar usuario: {username}",
|
"title": "Editar usuario: {username}",
|
||||||
@@ -2695,11 +2709,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Postuler pour {hotel}",
|
"title": "Postuler pour {hotel}",
|
||||||
@@ -1081,7 +1082,15 @@
|
|||||||
"colTimestamp": "Horodatage",
|
"colTimestamp": "Horodatage",
|
||||||
"colActions": "Actions",
|
"colActions": "Actions",
|
||||||
"photoAlt": "Photo utilisateur #{id}",
|
"photoAlt": "Photo utilisateur #{id}",
|
||||||
"byUser": "par {username}"
|
"byUser": "par {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Utilisateurs",
|
"title": "Utilisateurs",
|
||||||
@@ -1128,7 +1137,12 @@
|
|||||||
"banUser": "Bannir l'utilisateur",
|
"banUser": "Bannir l'utilisateur",
|
||||||
"resetPassword": "Réinitialiser le mot de passe",
|
"resetPassword": "Réinitialiser le mot de passe",
|
||||||
"deleteUser": "Supprimer l'utilisateur",
|
"deleteUser": "Supprimer l'utilisateur",
|
||||||
"confirmDelete": "Êtes-vous sûr de vouloir supprimer {username} ? Cette action est irréversible."
|
"confirmDelete": "Êtes-vous sûr de vouloir supprimer {username} ? Cette action est irréversible.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Modifier l'utilisateur : {username}",
|
"title": "Modifier l'utilisateur : {username}",
|
||||||
@@ -2695,11 +2709,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Prijavite se za osoblje {hotel}",
|
"title": "Prijavite se za osoblje {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Vremenska oznaka",
|
"colTimestamp": "Vremenska oznaka",
|
||||||
"colActions": "Radnje",
|
"colActions": "Radnje",
|
||||||
"photoAlt": "Korisnička fotografija #{id}",
|
"photoAlt": "Korisnička fotografija #{id}",
|
||||||
"byUser": "od {username}"
|
"byUser": "od {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Korisnici",
|
"title": "Korisnici",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Ban korisnika",
|
"banUser": "Ban korisnika",
|
||||||
"resetPassword": "Resetiraj lozinku",
|
"resetPassword": "Resetiraj lozinku",
|
||||||
"deleteUser": "Izbriši korisnika",
|
"deleteUser": "Izbriši korisnika",
|
||||||
"confirmDelete": "Jeste li sigurni da želite izbrisati {username}? Ovo se ne može poništiti."
|
"confirmDelete": "Jeste li sigurni da želite izbrisati {username}? Ovo se ne može poništiti.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Uredi korisnika: {username}",
|
"title": "Uredi korisnika: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Jelentkezzen a {hotel} személyzetére",
|
"title": "Jelentkezzen a {hotel} személyzetére",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Időbélyeg",
|
"colTimestamp": "Időbélyeg",
|
||||||
"colActions": "Akciók",
|
"colActions": "Akciók",
|
||||||
"photoAlt": "Felhasználói fotó #{id}",
|
"photoAlt": "Felhasználói fotó #{id}",
|
||||||
"byUser": "szerző: {username}"
|
"byUser": "szerző: {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Felhasználók",
|
"title": "Felhasználók",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Felhasználó kitiltása",
|
"banUser": "Felhasználó kitiltása",
|
||||||
"resetPassword": "Jelszó visszaállítása",
|
"resetPassword": "Jelszó visszaállítása",
|
||||||
"deleteUser": "Felhasználó törlése",
|
"deleteUser": "Felhasználó törlése",
|
||||||
"confirmDelete": "Biztosan törli a következőt: {username}? Ezt nem lehet visszavonni."
|
"confirmDelete": "Biztosan törli a következőt: {username}? Ezt nem lehet visszavonni.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Felhasználó szerkesztése: {username}",
|
"title": "Felhasználó szerkesztése: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -556,7 +556,8 @@
|
|||||||
"moderated": "Quel ticket è stato bloccato dalla moderazione.",
|
"moderated": "Quel ticket è stato bloccato dalla moderazione.",
|
||||||
"ratelimit": "Stai inviando troppo in fretta. Attendi un momento e riprova.",
|
"ratelimit": "Stai inviando troppo in fretta. Attendi un momento e riprova.",
|
||||||
"error": "Qualcosa è andato storto. Riprova."
|
"error": "Qualcosa è andato storto. Riprova."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"helpTicketDetail": {
|
"helpTicketDetail": {
|
||||||
"backToList": "← I tuoi ticket",
|
"backToList": "← I tuoi ticket",
|
||||||
@@ -1334,7 +1335,15 @@
|
|||||||
"colTimestamp": "Data",
|
"colTimestamp": "Data",
|
||||||
"colActions": "Azioni",
|
"colActions": "Azioni",
|
||||||
"photoAlt": "Foto utente #{id}",
|
"photoAlt": "Foto utente #{id}",
|
||||||
"byUser": "di {username}"
|
"byUser": "di {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Utenti",
|
"title": "Utenti",
|
||||||
@@ -1381,7 +1390,12 @@
|
|||||||
"banUser": "Banna utente",
|
"banUser": "Banna utente",
|
||||||
"resetPassword": "Reimposta password",
|
"resetPassword": "Reimposta password",
|
||||||
"deleteUser": "Elimina utente",
|
"deleteUser": "Elimina utente",
|
||||||
"confirmDelete": "Sei sicuro di voler eliminare {username}? Questa azione è irreversibile."
|
"confirmDelete": "Sei sicuro di voler eliminare {username}? Questa azione è irreversibile.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Modifica utente: {username}",
|
"title": "Modifica utente: {username}",
|
||||||
@@ -1518,11 +1532,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Risposta inviata.",
|
"replied": "Risposta inviata.",
|
||||||
"closed": "Ticket chiuso.",
|
"closed": "Ticket chiuso.",
|
||||||
"reopened": "Ticket riaperto."
|
"reopened": "Ticket riaperto.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "Questa coda e il help center pubblico. I ticket del supporto CMS stanno nella tab Supporto CMS.",
|
"queueHint": "Questa coda e il help center pubblico. I ticket del supporto CMS stanno nella tab Supporto CMS.",
|
||||||
"queueOtherCta": "Apri supporto CMS",
|
"queueOtherCta": "Apri supporto CMS",
|
||||||
"queueCounts": "Aperti qui: {here} · Supporto CMS: {other}"
|
"queueCounts": "Aperti qui: {here} · Supporto CMS: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"cfh": {
|
"cfh": {
|
||||||
"title": "Call for Help",
|
"title": "Call for Help",
|
||||||
|
|||||||
+22
-5
@@ -556,7 +556,8 @@
|
|||||||
"moderated": "Dat ticket is geblokkeerd door moderatie.",
|
"moderated": "Dat ticket is geblokkeerd door moderatie.",
|
||||||
"ratelimit": "Je dient te snel in. Wacht even en probeer opnieuw.",
|
"ratelimit": "Je dient te snel in. Wacht even en probeer opnieuw.",
|
||||||
"error": "Er ging iets mis. Probeer het opnieuw."
|
"error": "Er ging iets mis. Probeer het opnieuw."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"helpTicketDetail": {
|
"helpTicketDetail": {
|
||||||
"backToList": "← Jouw tickets",
|
"backToList": "← Jouw tickets",
|
||||||
@@ -1364,7 +1365,15 @@
|
|||||||
"colTimestamp": "Tijdstempel",
|
"colTimestamp": "Tijdstempel",
|
||||||
"colActions": "Acties",
|
"colActions": "Acties",
|
||||||
"photoAlt": "Gebruikersfoto #{id}",
|
"photoAlt": "Gebruikersfoto #{id}",
|
||||||
"byUser": "door {username}"
|
"byUser": "door {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Gebruikers",
|
"title": "Gebruikers",
|
||||||
@@ -1411,7 +1420,12 @@
|
|||||||
"banUser": "Gebruiker verbanne",
|
"banUser": "Gebruiker verbanne",
|
||||||
"resetPassword": "Wachtwoord resetten",
|
"resetPassword": "Wachtwoord resetten",
|
||||||
"deleteUser": "Gebruiker verwijderen",
|
"deleteUser": "Gebruiker verwijderen",
|
||||||
"confirmDelete": "Weet je zeker dat je {username} wilt verwijderen? Dit kan niet ongedaan worden gemaakt."
|
"confirmDelete": "Weet je zeker dat je {username} wilt verwijderen? Dit kan niet ongedaan worden gemaakt.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Gebruiker bewerken: {username}",
|
"title": "Gebruiker bewerken: {username}",
|
||||||
@@ -2902,11 +2916,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Antwoord verzonden.",
|
"replied": "Antwoord verzonden.",
|
||||||
"closed": "Ticket gesloten.",
|
"closed": "Ticket gesloten.",
|
||||||
"reopened": "Ticket heropend."
|
"reopened": "Ticket heropend.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "Deze wachtrij is het publieke helpcenter. CMS support desk tickets staan onder Supportbalie.",
|
"queueHint": "Deze wachtrij is het publieke helpcenter. CMS support desk tickets staan onder Supportbalie.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open hier: {here} · Supportbalie: {other}"
|
"queueCounts": "Open hier: {here} · Supportbalie: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"cfh": {
|
"cfh": {
|
||||||
"title": "Call for Help",
|
"title": "Call for Help",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Søk på {hotel}-ansatte",
|
"title": "Søk på {hotel}-ansatte",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Tidsstempel",
|
"colTimestamp": "Tidsstempel",
|
||||||
"colActions": "Handlinger",
|
"colActions": "Handlinger",
|
||||||
"photoAlt": "Brukerbilde nr. {id}",
|
"photoAlt": "Brukerbilde nr. {id}",
|
||||||
"byUser": "av {username}"
|
"byUser": "av {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Brukere",
|
"title": "Brukere",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Ban bruker",
|
"banUser": "Ban bruker",
|
||||||
"resetPassword": "Tilbakestill passord",
|
"resetPassword": "Tilbakestill passord",
|
||||||
"deleteUser": "Slett bruker",
|
"deleteUser": "Slett bruker",
|
||||||
"confirmDelete": "Er du sikker på at du vil slette {username}? Dette kan ikke angres."
|
"confirmDelete": "Er du sikker på at du vil slette {username}? Dette kan ikke angres.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Rediger bruker: {username}",
|
"title": "Rediger bruker: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Aplikuj na pracownika {hotel}",
|
"title": "Aplikuj na pracownika {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Znacznik czasu",
|
"colTimestamp": "Znacznik czasu",
|
||||||
"colActions": "Działania",
|
"colActions": "Działania",
|
||||||
"photoAlt": "Zdjęcie użytkownika nr{id}",
|
"photoAlt": "Zdjęcie użytkownika nr{id}",
|
||||||
"byUser": "przez: {username}"
|
"byUser": "przez: {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Użytkownicy",
|
"title": "Użytkownicy",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Zablokuj użytkownika",
|
"banUser": "Zablokuj użytkownika",
|
||||||
"resetPassword": "Zresetuj hasło",
|
"resetPassword": "Zresetuj hasło",
|
||||||
"deleteUser": "Usuń użytkownika",
|
"deleteUser": "Usuń użytkownika",
|
||||||
"confirmDelete": "Czy na pewno chcesz usunąć użytkownika {username}? Tego nie można cofnąć."
|
"confirmDelete": "Czy na pewno chcesz usunąć użytkownika {username}? Tego nie można cofnąć.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Edytuj użytkownika: {username}",
|
"title": "Edytuj użytkownika: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Inscreva-se para funcionários de {hotel}",
|
"title": "Inscreva-se para funcionários de {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Carimbo de data e hora",
|
"colTimestamp": "Carimbo de data e hora",
|
||||||
"colActions": "Ações",
|
"colActions": "Ações",
|
||||||
"photoAlt": "Foto do usuário #{id}",
|
"photoAlt": "Foto do usuário #{id}",
|
||||||
"byUser": "por {username}"
|
"byUser": "por {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Usuários",
|
"title": "Usuários",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Banir usuário",
|
"banUser": "Banir usuário",
|
||||||
"resetPassword": "Redefinir senha",
|
"resetPassword": "Redefinir senha",
|
||||||
"deleteUser": "Excluir usuário",
|
"deleteUser": "Excluir usuário",
|
||||||
"confirmDelete": "Tem certeza de que deseja excluir {username}? Isto não pode ser desfeito."
|
"confirmDelete": "Tem certeza de que deseja excluir {username}? Isto não pode ser desfeito.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Editar usuário: {username}",
|
"title": "Editar usuário: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Aplicați pentru personalul {hotel}",
|
"title": "Aplicați pentru personalul {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Marca temporală",
|
"colTimestamp": "Marca temporală",
|
||||||
"colActions": "Acțiuni",
|
"colActions": "Acțiuni",
|
||||||
"photoAlt": "Fotografia utilizatorului #{id}",
|
"photoAlt": "Fotografia utilizatorului #{id}",
|
||||||
"byUser": "de {username}"
|
"byUser": "de {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Utilizatori",
|
"title": "Utilizatori",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Ban utilizator",
|
"banUser": "Ban utilizator",
|
||||||
"resetPassword": "Resetează parola",
|
"resetPassword": "Resetează parola",
|
||||||
"deleteUser": "Ștergeți utilizatorul",
|
"deleteUser": "Ștergeți utilizatorul",
|
||||||
"confirmDelete": "Sigur doriți să ștergeți {username}? Acest lucru nu poate fi anulat."
|
"confirmDelete": "Sigur doriți să ștergeți {username}? Acest lucru nu poate fi anulat.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Editați utilizatorul: {username}",
|
"title": "Editați utilizatorul: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Подать заявку на персонал {hotel}",
|
"title": "Подать заявку на персонал {hotel}",
|
||||||
@@ -1109,7 +1110,15 @@
|
|||||||
"colTimestamp": "Метка времени",
|
"colTimestamp": "Метка времени",
|
||||||
"colActions": "Действия",
|
"colActions": "Действия",
|
||||||
"photoAlt": "Фото пользователя #{id}",
|
"photoAlt": "Фото пользователя #{id}",
|
||||||
"byUser": "на {username}"
|
"byUser": "на {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Пользователи",
|
"title": "Пользователи",
|
||||||
@@ -1156,7 +1165,12 @@
|
|||||||
"banUser": "Заблокировать пользователя",
|
"banUser": "Заблокировать пользователя",
|
||||||
"resetPassword": "Сбросить пароль",
|
"resetPassword": "Сбросить пароль",
|
||||||
"deleteUser": "Удалить пользователя",
|
"deleteUser": "Удалить пользователя",
|
||||||
"confirmDelete": "Вы уверены, что хотите удалить {username}? Это действие нельзя отменить."
|
"confirmDelete": "Вы уверены, что хотите удалить {username}? Это действие нельзя отменить.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Редактировать пользователя: {username}",
|
"title": "Редактировать пользователя: {username}",
|
||||||
@@ -2723,11 +2737,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Požiadajte o personál {hotel}",
|
"title": "Požiadajte o personál {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Časová pečiatka",
|
"colTimestamp": "Časová pečiatka",
|
||||||
"colActions": "Akcie",
|
"colActions": "Akcie",
|
||||||
"photoAlt": "Používateľská fotografia č. {id}",
|
"photoAlt": "Používateľská fotografia č. {id}",
|
||||||
"byUser": "od používateľa {username}"
|
"byUser": "od používateľa {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Používatelia",
|
"title": "Používatelia",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Zakázať používateľovi",
|
"banUser": "Zakázať používateľovi",
|
||||||
"resetPassword": "Obnoviť heslo",
|
"resetPassword": "Obnoviť heslo",
|
||||||
"deleteUser": "Odstrániť používateľa",
|
"deleteUser": "Odstrániť používateľa",
|
||||||
"confirmDelete": "Naozaj chcete odstrániť používateľa {username}? Toto sa nedá vrátiť späť."
|
"confirmDelete": "Naozaj chcete odstrániť používateľa {username}? Toto sa nedá vrátiť späť.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Upraviť používateľa: {username}",
|
"title": "Upraviť používateľa: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Пријавите се за особље {hotel}",
|
"title": "Пријавите се за особље {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Временска ознака",
|
"colTimestamp": "Временска ознака",
|
||||||
"colActions": "Акције",
|
"colActions": "Акције",
|
||||||
"photoAlt": "Корисничка фотографија #{id}",
|
"photoAlt": "Корисничка фотографија #{id}",
|
||||||
"byUser": "од {username}"
|
"byUser": "од {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Корисници",
|
"title": "Корисници",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Бан корисника",
|
"banUser": "Бан корисника",
|
||||||
"resetPassword": "Ресетујте лозинку",
|
"resetPassword": "Ресетујте лозинку",
|
||||||
"deleteUser": "Избриши корисника",
|
"deleteUser": "Избриши корисника",
|
||||||
"confirmDelete": "Are you sure you want to delete {username}? Ово се не може поништити."
|
"confirmDelete": "Are you sure you want to delete {username}? Ово се не може поништити.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Уреди корисника: {username}",
|
"title": "Уреди корисника: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Ansök om {hotel} personal",
|
"title": "Ansök om {hotel} personal",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Tidsstämpel",
|
"colTimestamp": "Tidsstämpel",
|
||||||
"colActions": "Åtgärder",
|
"colActions": "Åtgärder",
|
||||||
"photoAlt": "Användarfoto #{id}",
|
"photoAlt": "Användarfoto #{id}",
|
||||||
"byUser": "av {username}"
|
"byUser": "av {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Användare",
|
"title": "Användare",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Förbjud användare",
|
"banUser": "Förbjud användare",
|
||||||
"resetPassword": "Återställ lösenord",
|
"resetPassword": "Återställ lösenord",
|
||||||
"deleteUser": "Ta bort användare",
|
"deleteUser": "Ta bort användare",
|
||||||
"confirmDelete": "Är du säker på att du vill ta bort {username}? Detta kan inte ångras."
|
"confirmDelete": "Är du säker på att du vill ta bort {username}? Detta kan inte ångras.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Redigera användare: {username}",
|
"title": "Redigera användare: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "{hotel} personeli için başvur",
|
"title": "{hotel} personeli için başvur",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Zaman damgası",
|
"colTimestamp": "Zaman damgası",
|
||||||
"colActions": "Eylemler",
|
"colActions": "Eylemler",
|
||||||
"photoAlt": "Kullanıcı fotoğrafı #{id}",
|
"photoAlt": "Kullanıcı fotoğrafı #{id}",
|
||||||
"byUser": "{username} tarafından"
|
"byUser": "{username} tarafından",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Kullanıcılar",
|
"title": "Kullanıcılar",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Kullanıcıyı yasakla",
|
"banUser": "Kullanıcıyı yasakla",
|
||||||
"resetPassword": "Şifreyi sıfırla",
|
"resetPassword": "Şifreyi sıfırla",
|
||||||
"deleteUser": "Kullanıcıyı sil",
|
"deleteUser": "Kullanıcıyı sil",
|
||||||
"confirmDelete": "{username}'i silmek istediğinizden emin misiniz? Bu geri alınamaz."
|
"confirmDelete": "{username}'i silmek istediğinizden emin misiniz? Bu geri alınamaz.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Kullanıcıyı düzenle: {username}",
|
"title": "Kullanıcıyı düzenle: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
+22
-5
@@ -485,7 +485,8 @@
|
|||||||
"moderated": "That ticket was blocked by moderation.",
|
"moderated": "That ticket was blocked by moderation.",
|
||||||
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
"ratelimit": "You're submitting too fast. Please wait a moment and try again.",
|
||||||
"error": "Something went wrong. Please try again."
|
"error": "Something went wrong. Please try again."
|
||||||
}
|
},
|
||||||
|
"banAppealLabel": "This is a ban appeal"
|
||||||
},
|
},
|
||||||
"applyStaff": {
|
"applyStaff": {
|
||||||
"title": "Подайте заявку на роботу в {hotel}",
|
"title": "Подайте заявку на роботу в {hotel}",
|
||||||
@@ -1111,7 +1112,15 @@
|
|||||||
"colTimestamp": "Мітка часу",
|
"colTimestamp": "Мітка часу",
|
||||||
"colActions": "Дії",
|
"colActions": "Дії",
|
||||||
"photoAlt": "Фото користувача #{id}",
|
"photoAlt": "Фото користувача #{id}",
|
||||||
"byUser": "від {username}"
|
"byUser": "від {username}",
|
||||||
|
"photosShown": "Shown",
|
||||||
|
"rooms": "Rooms",
|
||||||
|
"users": "Users",
|
||||||
|
"distinctRooms": "Distinct rooms on this page",
|
||||||
|
"distinctPhotographers": "Distinct photographers on this page",
|
||||||
|
"total": "Total photos",
|
||||||
|
"recentPhotos": "Recent photos",
|
||||||
|
"pageOf": "Page {page} of {last} · {total} total"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"title": "Користувачі",
|
"title": "Користувачі",
|
||||||
@@ -1158,7 +1167,12 @@
|
|||||||
"banUser": "Забанити користувача",
|
"banUser": "Забанити користувача",
|
||||||
"resetPassword": "Скинути пароль",
|
"resetPassword": "Скинути пароль",
|
||||||
"deleteUser": "Видалити користувача",
|
"deleteUser": "Видалити користувача",
|
||||||
"confirmDelete": "Ви впевнені, що хочете видалити {username}? Це неможливо скасувати."
|
"confirmDelete": "Ви впевнені, що хочете видалити {username}? Це неможливо скасувати.",
|
||||||
|
"tabInfo": "Account Info",
|
||||||
|
"tabBadges": "Badges ({count})",
|
||||||
|
"tabRooms": "Rooms ({count})",
|
||||||
|
"tabSanctions": "Sanctions ({count})",
|
||||||
|
"tabActivity": "Activity"
|
||||||
},
|
},
|
||||||
"editForm": {
|
"editForm": {
|
||||||
"title": "Редагувати користувача: {username}",
|
"title": "Редагувати користувача: {username}",
|
||||||
@@ -2725,11 +2739,14 @@
|
|||||||
"success": {
|
"success": {
|
||||||
"replied": "Reply sent.",
|
"replied": "Reply sent.",
|
||||||
"closed": "Ticket closed.",
|
"closed": "Ticket closed.",
|
||||||
"reopened": "Ticket reopened."
|
"reopened": "Ticket reopened.",
|
||||||
|
"banLifted": "Ban lifted and ticket closed."
|
||||||
},
|
},
|
||||||
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
"queueHint": "This queue is the public help center. CMS support desk tickets are in the Support desk tab.",
|
||||||
"queueOtherCta": "Open CMS support desk",
|
"queueOtherCta": "Open CMS support desk",
|
||||||
"queueCounts": "Open here: {here} · Support desk: {other}"
|
"queueCounts": "Open here: {here} · Support desk: {other}",
|
||||||
|
"liftBanSubmit": "Lift requester ban & close",
|
||||||
|
"requesterBanned": "Requester banned"
|
||||||
},
|
},
|
||||||
"marketplace": {
|
"marketplace": {
|
||||||
"title": "Marketplace",
|
"title": "Marketplace",
|
||||||
|
|||||||
Reference in new issue
Block a user