microboard-ui-temp 0.1.164 → 0.1.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -235452,7 +235452,8 @@ var conf = {
235452
235452
  DECK_VERTICAL_OFFSET: 2,
235453
235453
  CARD_DIMENSIONS: { width: 250, height: 400 },
235454
235454
  DEFAULT_GAME_ITEM_DIMENSIONS: { width: 200, height: 200 },
235455
- MAX_CARD_SIZE: 500
235455
+ MAX_CARD_SIZE: 500,
235456
+ CONNECTOR_ITEM_OFFSET: 20
235456
235457
  };
235457
235458
  initDefaultI18N();
235458
235459
 
@@ -237008,7 +237009,7 @@ class SessionStorage {
237008
237009
  get(key) {
237009
237010
  const boardId = this.getBoardId() || "";
237010
237011
  const item = _sessionStorage.getItem(boardId + "_" + key);
237011
- if (!item) {
237012
+ if (!item || item === "undefined") {
237012
237013
  return;
237013
237014
  }
237014
237015
  return JSON.parse(item);
@@ -264395,7 +264396,6 @@ function getPointerMatrix(point5, angleRadians, scale = 0.3) {
264395
264396
  function radiansBetweenPoints(point1, point222) {
264396
264397
  return Math.atan2(point222.y - point1.y, point222.x - point1.x);
264397
264398
  }
264398
- var ITEM_OFFSET = 1;
264399
264399
  function getDirection2(from, to) {
264400
264400
  if (!to) {
264401
264401
  return null;
@@ -264438,7 +264438,7 @@ function getNeighbors(node22, grid, obstacles) {
264438
264438
  for (const pos of potentialNeighbors) {
264439
264439
  if (pos.x >= 0 && pos.x < grid.length && pos.y >= 0) {
264440
264440
  const newPoint = grid[pos.x][pos.y];
264441
- if (newPoint && !obstacles.some((obstacle) => obstacle.isAlmostInside(newPoint, ITEM_OFFSET - 1))) {
264441
+ if (newPoint && !obstacles.some((obstacle) => obstacle.isAlmostInside(newPoint, conf.CONNECTOR_ITEM_OFFSET - 1))) {
264442
264442
  neighbors.push({
264443
264443
  point: newPoint,
264444
264444
  costSoFar: 0,
@@ -264486,10 +264486,10 @@ function createGrid(start2, end2, toVisitPoints = []) {
264486
264486
  const endDir = getPointerDirection(end2);
264487
264487
  const revertMapDir = { top: 0, bottom: 1, right: 2, left: 3 };
264488
264488
  const offsetMap = {
264489
- top: { x: 0, y: -ITEM_OFFSET },
264490
- bottom: { x: 0, y: ITEM_OFFSET },
264491
- right: { x: ITEM_OFFSET, y: 0 },
264492
- left: { x: -ITEM_OFFSET, y: 0 }
264489
+ top: { x: 0, y: -conf.CONNECTOR_ITEM_OFFSET },
264490
+ bottom: { x: 0, y: conf.CONNECTOR_ITEM_OFFSET },
264491
+ right: { x: conf.CONNECTOR_ITEM_OFFSET, y: 0 },
264492
+ left: { x: -conf.CONNECTOR_ITEM_OFFSET, y: 0 }
264493
264493
  };
264494
264494
  const horizontalLines = [];
264495
264495
  const verticalLines = [];
@@ -264502,8 +264502,8 @@ function createGrid(start2, end2, toVisitPoints = []) {
264502
264502
  const newPoint = Object.create(Object.getPrototypeOf(point5), Object.getOwnPropertyDescriptors(point5));
264503
264503
  newPoint.x = pointOnMbr.x + offsetMap[dir2].x;
264504
264504
  newPoint.y = pointOnMbr.y + offsetMap[dir2].y;
264505
- verticalLines.push(mbrFloored.left - ITEM_OFFSET, mbrFloored.left, pointOnMbr.x, mbrFloored.right, mbrFloored.right + ITEM_OFFSET);
264506
- horizontalLines.push(mbrFloored.top - ITEM_OFFSET, mbrFloored.top, pointOnMbr.y, mbrFloored.bottom, mbrFloored.bottom + ITEM_OFFSET);
264505
+ verticalLines.push(mbrFloored.left - conf.CONNECTOR_ITEM_OFFSET, mbrFloored.left, pointOnMbr.x, mbrFloored.right, mbrFloored.right + conf.CONNECTOR_ITEM_OFFSET);
264506
+ horizontalLines.push(mbrFloored.top - conf.CONNECTOR_ITEM_OFFSET, mbrFloored.top, pointOnMbr.y, mbrFloored.bottom, mbrFloored.bottom + conf.CONNECTOR_ITEM_OFFSET);
264507
264507
  return newPoint;
264508
264508
  };
264509
264509
  if (start2.pointType !== "Board" && startDir) {
@@ -268897,80 +268897,72 @@ async function sha2563(message) {
268897
268897
  const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
268898
268898
  return hashHex;
268899
268899
  }
268900
- async function fileTosha256(file) {
268901
- const buffer = await file.arrayBuffer();
268902
- const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
268903
- const hashArray = Array.from(new Uint8Array(hashBuffer));
268904
- return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
268905
- }
268906
- var uploadMediaToStorage = async (hash2, blob, accessToken, boardId, type) => {
268900
+ var uploadSvgDirectly = async (blob, accessToken, boardId) => {
268901
+ const response = await fetch(`/api/v1/media/svg/${boardId}`, {
268902
+ method: "POST",
268903
+ headers: {
268904
+ "Content-Type": "image/svg+xml",
268905
+ Authorization: `Bearer ${accessToken}`
268906
+ },
268907
+ body: blob
268908
+ });
268909
+ if (!response.ok) {
268910
+ conf.hooks.onUploadMediaError(response, "image");
268911
+ throw new Error(`Failed to upload SVG. Status: ${response.status}`);
268912
+ }
268913
+ const data = await response.json();
268914
+ if (!data.url) {
268915
+ throw new Error("Server did not provide a key for the uploaded SVG.");
268916
+ }
268917
+ return data.url;
268918
+ };
268919
+ var uploadWithPresignedUrl = async (blob, accessToken, boardId, type) => {
268920
+ const generateUrlResponse = await fetch(`/api/v1/media/upload`, {
268921
+ method: "POST",
268922
+ headers: {
268923
+ "Content-Type": "application/json",
268924
+ Authorization: `Bearer ${accessToken}`
268925
+ },
268926
+ body: JSON.stringify({
268927
+ fileSize: blob.size,
268928
+ fileType: blob.type,
268929
+ boardId
268930
+ })
268931
+ });
268932
+ if (!generateUrlResponse.ok) {
268933
+ conf.hooks.onUploadMediaError(generateUrlResponse, type);
268934
+ throw new Error(`Failed to get presigned URL. Status: ${generateUrlResponse.status}`);
268935
+ }
268936
+ const data = await generateUrlResponse.json();
268937
+ const { uploadUrl, url } = data;
268938
+ if (!uploadUrl || !url) {
268939
+ throw new Error("Server did not provide an uploadUrl or key in the response.");
268940
+ }
268941
+ const uploadResponse = await fetch(uploadUrl, {
268942
+ method: "PUT",
268943
+ headers: {
268944
+ "Content-Type": blob.type
268945
+ },
268946
+ body: blob
268947
+ });
268948
+ if (!uploadResponse.ok) {
268949
+ console.error("Direct upload to storage failed:", uploadResponse.status, uploadResponse.statusText);
268950
+ throw new Error(`Direct upload to storage failed. Status: ${uploadResponse.status}`);
268951
+ }
268952
+ return url;
268953
+ };
268954
+ var uploadMediaToStorage = async (blob, accessToken, boardId, type) => {
268907
268955
  try {
268908
- const generateUrlResponse = await fetch(`${window.location.origin}/api/v1/media/generate-upload-url`, {
268909
- method: "POST",
268910
- headers: {
268911
- "Content-Type": "application/json",
268912
- Authorization: `Bearer ${accessToken}`
268913
- },
268914
- body: JSON.stringify({
268915
- fileSize: blob.size,
268916
- boardId,
268917
- hash: hash2
268918
- })
268919
- });
268920
- if (!generateUrlResponse.ok) {
268921
- conf.hooks.onUploadMediaError(generateUrlResponse, type);
268922
- throw new Error(`Failed to get presigned URL. Status: ${generateUrlResponse.status}`);
268923
- }
268924
- const data = await generateUrlResponse.json();
268925
- if (data.mediaUrl) {
268926
- console.log("Media already exists, skipping upload.");
268927
- return data.mediaUrl;
268928
- }
268929
- const { uploadUrl, promisedMediaUrl } = data;
268930
- if (!uploadUrl || !promisedMediaUrl) {
268931
- throw new Error("Server did not provide an uploadUrl or promisedMediaUrl in the response.");
268932
- }
268933
- const uploadResponse = await fetch(uploadUrl, {
268934
- method: "PUT",
268935
- headers: {
268936
- "Content-Type": blob.type
268937
- },
268938
- body: blob
268939
- });
268940
- if (!uploadResponse.ok) {
268941
- console.error("Direct upload to storage failed:", uploadResponse.status, uploadResponse.statusText);
268942
- throw new Error(`Direct upload to storage failed. Status: ${uploadResponse.status}`);
268956
+ if (blob.type === "image/svg+xml") {
268957
+ return await uploadSvgDirectly(blob, accessToken, boardId);
268958
+ } else {
268959
+ return await uploadWithPresignedUrl(blob, accessToken, boardId, type);
268943
268960
  }
268944
- return promisedMediaUrl;
268945
268961
  } catch (error) {
268946
268962
  console.error("Media upload process error:", error);
268947
268963
  throw error;
268948
268964
  }
268949
268965
  };
268950
- var uploadToTheStorage = async (hash2, dataURL, accessToken, boardId) => {
268951
- return new Promise((resolve2, reject) => {
268952
- const { blob, mimeType } = getBlobFromDataURL(dataURL);
268953
- fetch(`${window?.location.origin}/api/v1/media/image/${boardId}`, {
268954
- method: "POST",
268955
- headers: {
268956
- "Content-Type": mimeType,
268957
- "X-Image-Id": hash2,
268958
- Authorization: `Bearer ${accessToken}`
268959
- },
268960
- body: blob
268961
- }).then(async (response) => {
268962
- if (response.status !== 200) {
268963
- return conf.hooks.onUploadMediaError(response, "image");
268964
- }
268965
- return response.json();
268966
- }).then((data) => {
268967
- resolve2(data.src);
268968
- }).catch((error) => {
268969
- console.error("Media storage error:", error);
268970
- reject(error);
268971
- });
268972
- });
268973
- };
268974
268966
  var getBlobFromDataURL = (dataURL) => {
268975
268967
  const base64String = dataURL.split(",")[1];
268976
268968
  const mimeType = dataURL.split(",")[0].split(":")[1].split(";")[0];
@@ -269047,16 +269039,7 @@ var resizeAndConvertToPng = async (inp) => {
269047
269039
  };
269048
269040
  var prepareImage = (inp, accessToken, boardId) => resizeAndConvertToPng(inp).then(({ width: width2, height: height2, dataURL, hash: hash2 }) => {
269049
269041
  const { blob, mimeType } = getBlobFromDataURL(dataURL);
269050
- if (mimeType === "image/svg+xml") {
269051
- return uploadToTheStorage(hash2, dataURL, accessToken, boardId).then((src) => {
269052
- return {
269053
- imageDimension: { width: width2, height: height2 },
269054
- base64: dataURL,
269055
- storageLink: src
269056
- };
269057
- });
269058
- }
269059
- return uploadMediaToStorage(hash2, blob, accessToken, boardId, "image").then((src) => {
269042
+ return uploadMediaToStorage(blob, accessToken, boardId, "image").then((src) => {
269060
269043
  return {
269061
269044
  imageDimension: { width: width2, height: height2 },
269062
269045
  base64: dataURL,
@@ -269101,16 +269084,12 @@ var prepareVideo = (file, accessToken, boardId) => {
269101
269084
  video.onseeked = () => {
269102
269085
  video.onseeked = null;
269103
269086
  prepareImage(captureFrame(0.1, video)?.src, accessToken, boardId).then((imageData) => {
269104
- fileTosha256(file).then((hash2) => {
269105
- uploadMediaToStorage(hash2, file, accessToken, boardId, "video").then((url) => {
269106
- resolve2({
269107
- url,
269108
- previewUrl: imageData.storageLink
269109
- });
269110
- }).catch(reject);
269111
- }).catch(() => {
269112
- reject(new Error("Failed to generate hash"));
269113
- });
269087
+ uploadMediaToStorage(file, accessToken, boardId, "video").then((url) => {
269088
+ resolve2({
269089
+ url,
269090
+ previewUrl: imageData.storageLink
269091
+ });
269092
+ }).catch(reject);
269114
269093
  }).catch(() => reject(new Error("Failed to load video preview")));
269115
269094
  };
269116
269095
  video.currentTime = 0.1;
@@ -269407,13 +269386,9 @@ var prepareAudio = (file, accessToken, boardId) => {
269407
269386
  const audio = document.createElement("audio");
269408
269387
  audio.src = URL.createObjectURL(file);
269409
269388
  audio.onloadedmetadata = () => {
269410
- fileTosha256(file).then((hash2) => {
269411
- uploadMediaToStorage(hash2, file, accessToken, boardId, "audio").then((url) => {
269412
- resolve2(url);
269413
- }).catch(reject);
269414
- }).catch(() => {
269415
- reject(new Error("Failed to generate hash"));
269416
- });
269389
+ uploadMediaToStorage(file, accessToken, boardId, "audio").then((url) => {
269390
+ resolve2(url);
269391
+ }).catch(reject);
269417
269392
  };
269418
269393
  audio.onerror = () => {
269419
269394
  reject(new Error("Failed to load audio"));
@@ -280951,7 +280926,7 @@ class BoardSelection {
280951
280926
  if (!text5) {
280952
280927
  return;
280953
280928
  }
280954
- tempStorage.setVerticalAlignment(item.itemType, verticalAlignment);
280929
+ tempStorage.setVerticalAlignment(item.itemType, verticalAlignment || "top");
280955
280930
  if (item instanceof RichText) {
280956
280931
  item.setEditorFocus(this.context);
280957
280932
  }
@@ -281884,6 +281859,10 @@ class Board {
281884
281859
  itemData.endPoint.x += -minX + x;
281885
281860
  itemData.endPoint.y += -minY + y;
281886
281861
  }
281862
+ if (itemData.middlePoint?.pointType === "Board") {
281863
+ itemData.middlePoint.x += -minX + x;
281864
+ itemData.middlePoint.y += -minY + y;
281865
+ }
281887
281866
  } else if (itemData.transformation) {
281888
281867
  itemData.transformation.translateX = translateX - minX + x;
281889
281868
  itemData.transformation.translateY = translateY - minY + y;
@@ -289097,6 +289076,7 @@ __export(exports_boards, {
289097
289076
  manageAccess: () => manageAccess,
289098
289077
  grantAccess: () => grantAccess,
289099
289078
  getGrantedUsers: () => getGrantedUsers,
289079
+ getBoardsWithUsers: () => getBoardsWithUsers,
289100
289080
  getBoard: () => getBoard,
289101
289081
  getAccessKeys: () => getAccessKeys,
289102
289082
  getAccessKey: () => getAccessKey,
@@ -289239,6 +289219,18 @@ async function publishSnapshot(HTMLSnapshot, snapshotUId, boardUId) {
289239
289219
  }
289240
289220
  return data;
289241
289221
  }
289222
+ async function getBoardsWithUsers(page, pageSize, boardId) {
289223
+ const query = {
289224
+ page: String(page),
289225
+ pageSize: String(pageSize)
289226
+ };
289227
+ if (boardId && boardId.trim() !== "") {
289228
+ query["uuid"] = boardId.trim();
289229
+ }
289230
+ return api.get("/boards", {
289231
+ query
289232
+ });
289233
+ }
289242
289234
  // src/shared/api/folders/index.ts
289243
289235
  var exports_folders = {};
289244
289236
  __export(exports_folders, {
@@ -335923,6 +335915,7 @@ Upgrade to Plus to increase the limit and keep working`,
335923
335915
  passwordChanged: "Password changed successfully",
335924
335916
  addEmail: "Add Email",
335925
335917
  support: "Support",
335918
+ adminPanel: "Admin panel",
335926
335919
  logout: "Logout",
335927
335920
  name: "Name",
335928
335921
  email: "Email Address",
@@ -337179,6 +337172,7 @@ var ru_default = {
337179
337172
  passwordChanged: "Пароль успешно изменен",
337180
337173
  addEmail: "Добавить",
337181
337174
  support: "Поддержка",
337175
+ adminPanel: "Панель администратора",
337182
337176
  logout: "Выйти",
337183
337177
  name: "Имя",
337184
337178
  email: "Электронная почта",
@@ -358612,7 +358606,7 @@ var INITIAL_GEOMETRY = {
358612
358606
  };
358613
358607
  var TEXT_VERTICAL_ALIGNMENT = {
358614
358608
  top: "top",
358615
- middle: "center",
358609
+ center: "center",
358616
358610
  bottom: "bottom"
358617
358611
  };
358618
358612
  var STICKER_COLOR = {
@@ -360201,7 +360195,7 @@ class SessionStorage2 {
360201
360195
  get(key) {
360202
360196
  const boardId = this.getBoardId() || "";
360203
360197
  const item = _sessionStorage2.getItem(boardId + "_" + key);
360204
- if (!item) {
360198
+ if (!item || item === "undefined") {
360205
360199
  return;
360206
360200
  }
360207
360201
  return JSON.parse(item);
@@ -361060,7 +361054,7 @@ class Location {
361060
361054
  }
361061
361055
 
361062
361056
  // src/App/router.tsx
361063
- var import_react447 = __toESM(require_react(), 1);
361057
+ var import_react452 = __toESM(require_react(), 1);
361064
361058
 
361065
361059
  // src/entities/AIInput/utils.ts
361066
361060
  var PLACEHOLDER_OFFSET = "\t\t\t\t\t\t\t\t\t\t\t\t";
@@ -366218,7 +366212,7 @@ function SearchInput({
366218
366212
  // src/features/ShareModal/SharePanel.tsx
366219
366213
  var MODE_SELECTOR_OPTIONS = [
366220
366214
  {
366221
- label: instance2.t("sharing.accessOptions.edit"),
366215
+ label: conf.i18n.t("sharing.accessOptions.edit"),
366222
366216
  value: "edit",
366223
366217
  icon: /* @__PURE__ */ import_react197.default.createElement(Icon, {
366224
366218
  width: 20,
@@ -366227,7 +366221,7 @@ var MODE_SELECTOR_OPTIONS = [
366227
366221
  })
366228
366222
  },
366229
366223
  {
366230
- label: instance2.t("sharing.accessOptions.view"),
366224
+ label: conf.i18n.t("sharing.accessOptions.view"),
366231
366225
  value: "view",
366232
366226
  icon: /* @__PURE__ */ import_react197.default.createElement(Icon, {
366233
366227
  width: 20,
@@ -366270,7 +366264,10 @@ var SharePanel = import_react197.forwardRef(({
366270
366264
  }, /* @__PURE__ */ import_react197.default.createElement(UiButton, {
366271
366265
  variant: "secondary",
366272
366266
  className: clsx_default(SharePanel_module_default.closeBtn),
366273
- onClick: toggleIsOpen
366267
+ onClick: (evt) => {
366268
+ evt.stopPropagation();
366269
+ toggleIsOpen();
366270
+ }
366274
366271
  }, /* @__PURE__ */ import_react197.default.createElement(Icon, {
366275
366272
  width: 28,
366276
366273
  height: 28,
@@ -376176,21 +376173,21 @@ function ImportMiro() {
376176
376173
  const authCode = searchParams.get("code");
376177
376174
  const teamIdSearch = searchParams.get("team_id");
376178
376175
  const { openModal: openModal2 } = useUiModalContext();
376179
- const fetchToken = async () => {
376176
+ const fetchToken = async (authCode2) => {
376180
376177
  try {
376181
- const clientId = globalThis.__ENV__?.MIRO_CLIENT_ID ?? "";
376182
- const clientSecret = globalThis.__ENV__?.MIRO_CLIENT_SECRET ?? "";
376183
- const redirectRoute = "/boards/blank?clipboard=true";
376184
- const redirectUrl = window.location.origin + redirectRoute;
376185
- const response = await fetch(getApiUrl("/miro/token" + "?grant_type=authorization_code&client_id=" + clientId + "&client_secret=" + clientSecret + "&code=" + authCode + "&redirect_uri=" + redirectUrl), {
376178
+ const response = await fetch(getApiUrl("/miro/get-token"), {
376186
376179
  method: "POST",
376187
376180
  headers: {
376188
- Accept: "application/json, application/*+json, application/x-jackson-smile, application/cbor"
376189
- }
376181
+ "Content-Type": "application/json"
376182
+ },
376183
+ body: JSON.stringify({ code: authCode2 })
376190
376184
  });
376191
- const token = await response.json();
376192
- if (token) {
376193
- api10.set("miro_accessToken", token.access_token);
376185
+ if (!response.ok) {
376186
+ throw new Error("Error getting token");
376187
+ }
376188
+ const tokenData = await response.json();
376189
+ if (tokenData && tokenData.access_token) {
376190
+ api10.set("miro_accessToken", tokenData.access_token);
376194
376191
  openSeenLastBoard();
376195
376192
  }
376196
376193
  } catch (error3) {
@@ -376219,7 +376216,7 @@ function ImportMiro() {
376219
376216
  return;
376220
376217
  }
376221
376218
  if (!token || token === "undefined") {
376222
- fetchToken();
376219
+ fetchToken(authCode);
376223
376220
  }
376224
376221
  if (token && token !== "undefined") {
376225
376222
  openSeenLastBoard();
@@ -440880,6 +440877,20 @@ var UserDropDown = ({
440880
440877
  })));
440881
440878
  };
440882
440879
 
440880
+ // src/entities/account/ComponentRolesGuard.tsx
440881
+ function ComponentRolesGuard({ allowedRoles, children }) {
440882
+ const account = useAccount2();
440883
+ if (!account.isInitialized) {
440884
+ return null;
440885
+ }
440886
+ const userRole = account.tokenData?.role;
440887
+ if (userRole && allowedRoles.includes(userRole)) {
440888
+ return children;
440889
+ } else {
440890
+ return null;
440891
+ }
440892
+ }
440893
+
440883
440894
  // src/features/UserPanel/UserPic/UserPic.tsx
440884
440895
  var UserPic = ({ ...props }) => {
440885
440896
  const { t: t11 } = useTranslation();
@@ -440911,6 +440922,11 @@ var UserPic = ({ ...props }) => {
440911
440922
  ev.stopPropagation();
440912
440923
  window.open("https://x.com/Microboard_io", "_blank");
440913
440924
  };
440925
+ const handleOpenAdminPage = (ev) => {
440926
+ ev.preventDefault();
440927
+ ev.stopPropagation();
440928
+ navigate("/admin");
440929
+ };
440914
440930
  return /* @__PURE__ */ import_react374.default.createElement(import_react374.default.Fragment, null, /* @__PURE__ */ import_react374.default.createElement("div", {
440915
440931
  className: UserPanel_module_default.userPicWrapper,
440916
440932
  ref: userPanelRef,
@@ -440978,9 +440994,24 @@ var UserPic = ({ ...props }) => {
440978
440994
  }), " ", /* @__PURE__ */ import_react374.default.createElement("span", {
440979
440995
  className: UserPanel_module_default.userDropDownButton
440980
440996
  }, t11("profile.support"))),
440981
- /* @__PURE__ */ import_react374.default.createElement(UiButton, {
440997
+ /* @__PURE__ */ import_react374.default.createElement(ComponentRolesGuard, {
440998
+ allowedRoles: ["ADMIN" /* ADMIN */]
440999
+ }, /* @__PURE__ */ import_react374.default.createElement(UiButton, {
440982
441000
  type: "button",
440983
441001
  key: "userDropDown3",
441002
+ onClick: handleOpenAdminPage,
441003
+ variant: "ghost",
441004
+ size: "lg"
441005
+ }, /* @__PURE__ */ import_react374.default.createElement(Icon, {
441006
+ width: 20,
441007
+ height: 20,
441008
+ iconName: "Admin"
441009
+ }), " ", /* @__PURE__ */ import_react374.default.createElement("span", {
441010
+ className: UserPanel_module_default.userDropDownButton
441011
+ }, t11("profile.adminPanel")))),
441012
+ /* @__PURE__ */ import_react374.default.createElement(UiButton, {
441013
+ type: "button",
441014
+ key: "userDropDown4",
440984
441015
  onClick: handleLogout,
440985
441016
  variant: "ghost",
440986
441017
  size: "lg"
@@ -444362,6 +444393,8 @@ var AudioPlayer = ({ item }) => {
444362
444393
  const [isProgressBarDown, setIsProgressBarDown] = import_react419.useState(false);
444363
444394
  const [openedMenu, setOpenedMenu] = import_react419.useState("none");
444364
444395
  const [isMetadataLoaded, setIsMetadataLoaded] = import_react419.useState(false);
444396
+ const [resolvedAudioUrl, setResolvedAudioUrl] = import_react419.useState(null);
444397
+ const [isLoadingUrl, setIsLoadingUrl] = import_react419.useState(true);
444365
444398
  const audioRef = import_react419.useRef(null);
444366
444399
  const containerRef = import_react419.useRef(null);
444367
444400
  const progressBarRef = import_react419.useRef(null);
@@ -444371,8 +444404,43 @@ var AudioPlayer = ({ item }) => {
444371
444404
  const volumeBtnRef = import_react419.useRef(null);
444372
444405
  const { t: t11 } = useTranslation();
444373
444406
  const isPlaying = item.getIsPlaying();
444374
- const isDisabled = !isMetadataLoaded || !item.getUrl();
444407
+ const isDisabled = isLoadingUrl || !isMetadataLoaded || !resolvedAudioUrl;
444408
+ const account = useAccount2();
444375
444409
  const optionsRef = useClickOutside(() => setOpenedMenu("none"), [extraOptionsBtnRef, playbackRateBtnRef], true);
444410
+ import_react419.useEffect(() => {
444411
+ setResolvedAudioUrl(null);
444412
+ setIsLoadingUrl(true);
444413
+ setIsMetadataLoaded(false);
444414
+ const apiUrl = item.getUrl();
444415
+ if (!apiUrl || !account.accessToken) {
444416
+ setIsLoadingUrl(false);
444417
+ return;
444418
+ }
444419
+ let isMounted = true;
444420
+ const resolveRedirectUrl = async () => {
444421
+ try {
444422
+ const response = await fetch(apiUrl, {
444423
+ method: "HEAD",
444424
+ headers: {
444425
+ Authorization: `Bearer ${account.accessToken}`
444426
+ }
444427
+ });
444428
+ if (isMounted) {
444429
+ setResolvedAudioUrl(response.url);
444430
+ }
444431
+ } catch (error3) {
444432
+ console.error("Error resolving redirect URL:", error3);
444433
+ } finally {
444434
+ if (isMounted) {
444435
+ setIsLoadingUrl(false);
444436
+ }
444437
+ }
444438
+ };
444439
+ resolveRedirectUrl();
444440
+ return () => {
444441
+ isMounted = false;
444442
+ };
444443
+ }, [item.getUrl(), account.accessToken]);
444376
444444
  import_react419.useEffect(() => {
444377
444445
  const audio = audioRef.current;
444378
444446
  if (!audio) {
@@ -444510,7 +444578,7 @@ var AudioPlayer = ({ item }) => {
444510
444578
  }), /* @__PURE__ */ import_react419.default.createElement("audio", {
444511
444579
  ref: audioRef,
444512
444580
  className: AudioPlayer_module_default.displayNone,
444513
- src: item.getUrl(),
444581
+ src: resolvedAudioUrl || "",
444514
444582
  onEnded,
444515
444583
  onTimeUpdate,
444516
444584
  onLoadedData,
@@ -447637,6 +447705,9 @@ var sprite_default = `<svg width="0" height="0" class="hidden">
447637
447705
  </path>
447638
447706
  </g>
447639
447707
  </symbol>
447708
+ <symbol id="Admin" viewBox="0 0 18 21" fill="none" xmlns="http://www.w3.org/2000/svg">
447709
+ <path d="M8 13V15C6.4087 15 4.88258 15.6321 3.75736 16.7574C2.63214 17.8826 2 19.4087 2 21H0C0 18.8783 0.842855 16.8434 2.34315 15.3431C3.84344 13.8429 5.87827 13 8 13ZM8 12C4.685 12 2 9.315 2 6C2 2.685 4.685 0 8 0C11.315 0 14 2.685 14 6C14 9.315 11.315 12 8 12ZM8 10C10.21 10 12 8.21 12 6C12 3.79 10.21 2 8 2C5.79 2 4 3.79 4 6C4 8.21 5.79 10 8 10ZM17 16H18V21H10V16H11V15C11 14.2044 11.3161 13.4413 11.8787 12.8787C12.4413 12.3161 13.2044 12 14 12C14.7956 12 15.5587 12.3161 16.1213 12.8787C16.6839 13.4413 17 14.2044 17 15V16ZM15 16V15C15 14.7348 14.8946 14.4804 14.7071 14.2929C14.5196 14.1054 14.2652 14 14 14C13.7348 14 13.4804 14.1054 13.2929 14.2929C13.1054 14.4804 13 14.7348 13 15V16H15Z" fill="currentColor"/>
447710
+ </symbol>
447640
447711
 
447641
447712
  </svg>
447642
447713
  `;
@@ -449066,47 +449137,569 @@ var WheelEventLoggerPage = () => {
449066
449137
 
449067
449138
  // src/App/router.tsx
449068
449139
  var import_client2 = __toESM(require_client(), 1);
449140
+
449141
+ // src/pages/AdminPage/AdminPage.tsx
449142
+ var import_react450 = __toESM(require_react(), 1);
449143
+
449144
+ // src/pages/AdminPage/AdminPage.module.css
449145
+ var AdminPage_module_default = {
449146
+ adminDashboard: "adminDashboard_d3ewvA",
449147
+ header: "header_d3ewvA",
449148
+ dashboardTitle: "dashboardTitle_d3ewvA",
449149
+ searchBar: "searchBar_d3ewvA",
449150
+ customInput: "customInput_d3ewvA",
449151
+ customButton: "customButton_d3ewvA",
449152
+ buttonSecondary: "buttonSecondary_d3ewvA",
449153
+ buttonDanger: "buttonDanger_d3ewvA",
449154
+ disabled: "disabled_d3ewvA",
449155
+ errorAlert: "errorAlert_d3ewvA",
449156
+ tableContainer: "tableContainer_d3ewvA",
449157
+ customTable: "customTable_d3ewvA",
449158
+ loadingCell: "loadingCell_d3ewvA",
449159
+ noDataCell: "noDataCell_d3ewvA",
449160
+ actionButtons: "actionButtons_d3ewvA",
449161
+ statusTag: "statusTag_d3ewvA",
449162
+ statusPublic: "statusPublic_d3ewvA",
449163
+ statusPrivate: "statusPrivate_d3ewvA",
449164
+ searchBtn: "searchBtn_d3ewvA",
449165
+ pagination: "pagination_d3ewvA",
449166
+ backBtn: "backBtn_d3ewvA"
449167
+ };
449168
+
449169
+ // src/pages/AdminPage/ManageAccessModal/ManageAccessModal.tsx
449170
+ var import_react447 = __toESM(require_react(), 1);
449171
+
449172
+ // src/pages/AdminPage/ManageAccessModal/ManageAccessModal.module.css
449173
+ var ManageAccessModal_module_default = {
449174
+ modalContent: "modalContent_J7xl7w",
449175
+ title: "title_J7xl7w",
449176
+ form: "form_J7xl7w",
449177
+ formRow: "formRow_J7xl7w",
449178
+ label: "label_J7xl7w",
449179
+ switch: "switch_J7xl7w",
449180
+ slider: "slider_J7xl7w",
449181
+ switchLabel: "switchLabel_J7xl7w",
449182
+ select: "select_J7xl7w",
449183
+ tooltip: "tooltip_J7xl7w",
449184
+ tooltipText: "tooltipText_J7xl7w",
449185
+ infoAlert: "infoAlert_J7xl7w",
449186
+ errorAlert: "errorAlert_J7xl7w",
449187
+ footer: "footer_J7xl7w"
449188
+ };
449189
+
449190
+ // src/pages/AdminPage/ManageAccessModal/ManageAccessModal.tsx
449191
+ var MANAGE_ACCESS_MODAL = Symbol("manageAccessModal");
449192
+ function ManageAccessModal() {
449193
+ const { closeModal: closeModal2, data, setModalData: setModalData2 } = useUiModalContext();
449194
+ const { board, onSuccess } = data || {};
449195
+ const [loading, setLoading] = import_react447.useState(false);
449196
+ const [error3, setError] = import_react447.useState(null);
449197
+ const [isPublic, setIsPublic] = import_react447.useState(board?.isPublic || false);
449198
+ const [directAccessType, setDirectAccessType] = import_react447.useState("view" /* VIEW */);
449199
+ console.log(board, data);
449200
+ import_react447.useEffect(() => {
449201
+ if (board) {
449202
+ setIsPublic(board.isPublic);
449203
+ setDirectAccessType("view" /* VIEW */);
449204
+ }
449205
+ console.log(board);
449206
+ }, [board]);
449207
+ if (!board)
449208
+ return /* @__PURE__ */ import_react447.default.createElement(import_react447.default.Fragment, null);
449209
+ const handleSave = async () => {
449210
+ setLoading(true);
449211
+ setError(null);
449212
+ try {
449213
+ const usersPayload = board.users.map((user) => ({
449214
+ userId: user.id,
449215
+ email: user.email,
449216
+ accessType: user.permissions.includes("edit" /* Edit */) ? "edit" /* Edit */ : "view" /* View */
449217
+ }));
449218
+ const payload = {
449219
+ isPublic,
449220
+ directAccessType,
449221
+ users: usersPayload
449222
+ };
449223
+ await manageAccess(board.uuid, payload);
449224
+ if (onSuccess) {
449225
+ onSuccess();
449226
+ }
449227
+ setModalData2(undefined);
449228
+ closeModal2();
449229
+ } catch (err2) {
449230
+ console.error("Failed to manage access:", err2);
449231
+ setError("Не удалось обновить статус. Пожалуйста, попробуйте снова.");
449232
+ } finally {
449233
+ setLoading(false);
449234
+ }
449235
+ };
449236
+ const showAccessTypeSelector = !board.isPublic && isPublic;
449237
+ const showPrivacyWarning = board.isPublic && !isPublic;
449238
+ return /* @__PURE__ */ import_react447.default.createElement(UiModal, {
449239
+ modalId: MANAGE_ACCESS_MODAL,
449240
+ closeOnClickOutside: false,
449241
+ renderAsPageOnMobile: true
449242
+ }, /* @__PURE__ */ import_react447.default.createElement("div", {
449243
+ className: ManageAccessModal_module_default.modalContent
449244
+ }, /* @__PURE__ */ import_react447.default.createElement("div", {
449245
+ className: ManageAccessModal_module_default.title
449246
+ }, `Управление доступом: "${board.title}"`), error3 && /* @__PURE__ */ import_react447.default.createElement("div", {
449247
+ className: ManageAccessModal_module_default.errorAlert
449248
+ }, error3), /* @__PURE__ */ import_react447.default.createElement("div", {
449249
+ className: ManageAccessModal_module_default.form
449250
+ }, /* @__PURE__ */ import_react447.default.createElement("div", {
449251
+ className: ManageAccessModal_module_default.formRow
449252
+ }, /* @__PURE__ */ import_react447.default.createElement("label", {
449253
+ className: ManageAccessModal_module_default.label
449254
+ }, "Статус доски"), /* @__PURE__ */ import_react447.default.createElement("label", {
449255
+ className: ManageAccessModal_module_default.switch
449256
+ }, /* @__PURE__ */ import_react447.default.createElement("input", {
449257
+ type: "checkbox",
449258
+ checked: isPublic,
449259
+ onChange: (e15) => setIsPublic(e15.target.checked)
449260
+ }), /* @__PURE__ */ import_react447.default.createElement("span", {
449261
+ className: ManageAccessModal_module_default.slider
449262
+ })), /* @__PURE__ */ import_react447.default.createElement("span", {
449263
+ className: ManageAccessModal_module_default.switchLabel
449264
+ }, isPublic ? "Публичная" : "Приватная")), showAccessTypeSelector && /* @__PURE__ */ import_react447.default.createElement("div", {
449265
+ className: ManageAccessModal_module_default.formRow
449266
+ }, /* @__PURE__ */ import_react447.default.createElement("label", {
449267
+ htmlFor: "accessType",
449268
+ className: ManageAccessModal_module_default.label
449269
+ }, "Уровень доступа для всех", /* @__PURE__ */ import_react447.default.createElement("span", {
449270
+ className: ManageAccessModal_module_default.tooltip
449271
+ }, "?", /* @__PURE__ */ import_react447.default.createElement("span", {
449272
+ className: ManageAccessModal_module_default.tooltipText
449273
+ }, "Какой доступ получат все пользователи, у которых нет явных разрешений?"))), /* @__PURE__ */ import_react447.default.createElement("select", {
449274
+ id: "accessType",
449275
+ className: ManageAccessModal_module_default.select,
449276
+ value: directAccessType,
449277
+ onChange: (e15) => setDirectAccessType(e15.target.value)
449278
+ }, /* @__PURE__ */ import_react447.default.createElement("option", {
449279
+ value: "view" /* VIEW */
449280
+ }, "Только просмотр"), /* @__PURE__ */ import_react447.default.createElement("option", {
449281
+ value: "edit" /* EDIT */
449282
+ }, "Просмотр и редактирование"))), showPrivacyWarning && /* @__PURE__ */ import_react447.default.createElement("div", {
449283
+ className: ManageAccessModal_module_default.infoAlert
449284
+ }, "Пользователи с прямым доступом сохранят свои права после того, как доска станет приватной.")), /* @__PURE__ */ import_react447.default.createElement("div", {
449285
+ className: ManageAccessModal_module_default.footer
449286
+ }, /* @__PURE__ */ import_react447.default.createElement(UiButton, {
449287
+ variant: "secondary",
449288
+ onClick: () => {
449289
+ setModalData2(undefined);
449290
+ closeModal2();
449291
+ }
449292
+ }, "Отмена"), /* @__PURE__ */ import_react447.default.createElement(UiButton, {
449293
+ variant: "primary",
449294
+ onClick: handleSave,
449295
+ disabled: loading
449296
+ }, loading ? "Сохранение..." : "Сохранить"))));
449297
+ }
449298
+
449299
+ // src/pages/AdminPage/ManageUsersModal/ManageUsersModal.tsx
449300
+ var import_react448 = __toESM(require_react(), 1);
449301
+
449302
+ // src/pages/AdminPage/ManageUsersModal/ManageUsersModal.module.css
449303
+ var ManageUsersModal_module_default = {
449304
+ modalContent: "modalContent_T4M-EA",
449305
+ title: "title_T4M-EA",
449306
+ userList: "userList_T4M-EA",
449307
+ userRow: "userRow_T4M-EA",
449308
+ userEmail: "userEmail_T4M-EA",
449309
+ select: "select_T4M-EA",
449310
+ noUsers: "noUsers_T4M-EA",
449311
+ errorAlert: "errorAlert_T4M-EA",
449312
+ footer: "footer_T4M-EA"
449313
+ };
449314
+
449315
+ // src/pages/AdminPage/ManageUsersModal/ManageUsersModal.tsx
449316
+ var MANAGE_USERS_MODAL = Symbol("manageUsersModal");
449317
+ var getAccessType = (permissions) => {
449318
+ if (permissions.includes("edit" /* Edit */))
449319
+ return "edit" /* Edit */;
449320
+ if (permissions.includes("view" /* View */))
449321
+ return "view" /* View */;
449322
+ return "noAccess" /* NoAccess */;
449323
+ };
449324
+ function ManageUsersModal() {
449325
+ const { closeModal: closeModal2, data, setModalData: setModalData2 } = useUiModalContext();
449326
+ const { board, onSuccess } = data || {};
449327
+ const [editableUsers, setEditableUsers] = import_react448.useState([]);
449328
+ const [isSaving, setIsSaving] = import_react448.useState(false);
449329
+ const [error3, setError] = import_react448.useState(null);
449330
+ import_react448.useEffect(() => {
449331
+ if (board) {
449332
+ setEditableUsers(board.users.map((user) => ({
449333
+ ...user,
449334
+ accessType: getAccessType(user.permissions)
449335
+ })));
449336
+ }
449337
+ }, [board]);
449338
+ if (!board)
449339
+ return /* @__PURE__ */ import_react448.default.createElement(import_react448.default.Fragment, null);
449340
+ const handleAccessChange = (userId, newAccessType) => {
449341
+ setEditableUsers((currentUsers) => currentUsers.map((u10) => u10.id === userId ? { ...u10, accessType: newAccessType } : u10));
449342
+ };
449343
+ const handleSaveChanges = async () => {
449344
+ setIsSaving(true);
449345
+ setError(null);
449346
+ try {
449347
+ const payload = editableUsers.map((u10) => ({
449348
+ userId: u10.id,
449349
+ accessType: u10.accessType,
449350
+ email: u10.email || ""
449351
+ }));
449352
+ await grantAccess(board.uuid, payload);
449353
+ if (onSuccess) {
449354
+ onSuccess();
449355
+ }
449356
+ setModalData2(undefined);
449357
+ closeModal2();
449358
+ } catch (err2) {
449359
+ console.error(err2);
449360
+ setError("Ошибка при сохранении прав. Попробуйте снова.");
449361
+ } finally {
449362
+ setIsSaving(false);
449363
+ }
449364
+ };
449365
+ const handleClose = () => {
449366
+ setModalData2(undefined);
449367
+ closeModal2();
449368
+ };
449369
+ return /* @__PURE__ */ import_react448.default.createElement(UiModal, {
449370
+ modalId: MANAGE_USERS_MODAL,
449371
+ closeOnClickOutside: false,
449372
+ renderAsPageOnMobile: true
449373
+ }, /* @__PURE__ */ import_react448.default.createElement("div", {
449374
+ className: ManageUsersModal_module_default.modalContent
449375
+ }, /* @__PURE__ */ import_react448.default.createElement("div", {
449376
+ className: ManageUsersModal_module_default.title
449377
+ }, `Пользователи доски "${board.title}"`), error3 && /* @__PURE__ */ import_react448.default.createElement("div", {
449378
+ className: ManageUsersModal_module_default.errorAlert
449379
+ }, error3), /* @__PURE__ */ import_react448.default.createElement("div", {
449380
+ className: ManageUsersModal_module_default.userList
449381
+ }, editableUsers.map((user) => /* @__PURE__ */ import_react448.default.createElement("div", {
449382
+ key: user.id,
449383
+ className: ManageUsersModal_module_default.userRow
449384
+ }, /* @__PURE__ */ import_react448.default.createElement("span", {
449385
+ className: ManageUsersModal_module_default.userEmail
449386
+ }, user.email), /* @__PURE__ */ import_react448.default.createElement("select", {
449387
+ className: ManageUsersModal_module_default.select,
449388
+ value: user.accessType,
449389
+ onChange: (e15) => handleAccessChange(user.id, e15.target.value)
449390
+ }, /* @__PURE__ */ import_react448.default.createElement("option", {
449391
+ value: "edit" /* Edit */
449392
+ }, "Редактор"), /* @__PURE__ */ import_react448.default.createElement("option", {
449393
+ value: "view" /* View */
449394
+ }, "Читатель"), /* @__PURE__ */ import_react448.default.createElement("option", {
449395
+ value: "noAccess" /* NoAccess */
449396
+ }, "Нет доступа")))), editableUsers.length === 0 && /* @__PURE__ */ import_react448.default.createElement("div", {
449397
+ className: ManageUsersModal_module_default.noUsers
449398
+ }, "У этой доски нет пользователей с доступом.")), /* @__PURE__ */ import_react448.default.createElement("div", {
449399
+ className: ManageUsersModal_module_default.footer
449400
+ }, /* @__PURE__ */ import_react448.default.createElement(UiButton, {
449401
+ variant: "secondary",
449402
+ onClick: handleClose
449403
+ }, "Отмена"), /* @__PURE__ */ import_react448.default.createElement(UiButton, {
449404
+ variant: "primary",
449405
+ onClick: handleSaveChanges,
449406
+ disabled: isSaving
449407
+ }, isSaving ? "Сохранение..." : "Сохранить"))));
449408
+ }
449409
+
449410
+ // src/pages/AdminPage/ConfirmDeleteModal/ConfirmDeleteModal.tsx
449411
+ var import_react449 = __toESM(require_react(), 1);
449412
+
449413
+ // src/pages/AdminPage/ConfirmDeleteModal/ConfirmDeleteModal.module.css
449414
+ var ConfirmDeleteModal_module_default = {
449415
+ modalContent: "modalContent_X6J-gw",
449416
+ icon: "icon_X6J-gw",
449417
+ title: "title_X6J-gw",
449418
+ description: "description_X6J-gw",
449419
+ errorAlert: "errorAlert_X6J-gw",
449420
+ footer: "footer_X6J-gw",
449421
+ dangerButton: "dangerButton_X6J-gw"
449422
+ };
449423
+
449424
+ // src/pages/AdminPage/ConfirmDeleteModal/ConfirmDeleteModal.tsx
449425
+ var CONFIRM_DELETE_MODAL = Symbol("confirmDeleteModal");
449426
+ function ConfirmDeleteModal() {
449427
+ const { closeModal: closeModal2, data, setModalData: setModalData2 } = useUiModalContext();
449428
+ const { board, onSuccess } = data || {};
449429
+ const [isDeleting, setIsDeleting] = import_react449.useState(false);
449430
+ const [error3, setError] = import_react449.useState(null);
449431
+ if (!board)
449432
+ return /* @__PURE__ */ import_react449.default.createElement(import_react449.default.Fragment, null);
449433
+ const handleConfirmDelete = async () => {
449434
+ setIsDeleting(true);
449435
+ setError(null);
449436
+ try {
449437
+ await deleteBoard(board.uuid);
449438
+ if (onSuccess) {
449439
+ onSuccess();
449440
+ }
449441
+ setModalData2(undefined);
449442
+ closeModal2();
449443
+ } catch (err2) {
449444
+ console.error("Ошибка при удалении доски:", err2);
449445
+ setError("Не удалось удалить доску. Пожалуйста, попробуйте снова.");
449446
+ } finally {
449447
+ setIsDeleting(false);
449448
+ }
449449
+ };
449450
+ const handleClose = () => {
449451
+ setModalData2(undefined);
449452
+ closeModal2();
449453
+ };
449454
+ return /* @__PURE__ */ import_react449.default.createElement(UiModal, {
449455
+ modalId: CONFIRM_DELETE_MODAL,
449456
+ closeOnClickOutside: false,
449457
+ renderAsPageOnMobile: true
449458
+ }, /* @__PURE__ */ import_react449.default.createElement("div", {
449459
+ className: ConfirmDeleteModal_module_default.modalContent
449460
+ }, /* @__PURE__ */ import_react449.default.createElement("div", {
449461
+ className: ConfirmDeleteModal_module_default.title
449462
+ }, "Удаление доски"), /* @__PURE__ */ import_react449.default.createElement("p", {
449463
+ className: ConfirmDeleteModal_module_default.description
449464
+ }, "Вы уверены, что хотите удалить доску ", /* @__PURE__ */ import_react449.default.createElement("br", null), /* @__PURE__ */ import_react449.default.createElement("strong", null, '"', board.title, '"'), "?", /* @__PURE__ */ import_react449.default.createElement("br", null), /* @__PURE__ */ import_react449.default.createElement("br", null), "Это действие необратимо."), error3 && /* @__PURE__ */ import_react449.default.createElement("div", {
449465
+ className: ConfirmDeleteModal_module_default.errorAlert
449466
+ }, error3), /* @__PURE__ */ import_react449.default.createElement("div", {
449467
+ className: ConfirmDeleteModal_module_default.footer
449468
+ }, /* @__PURE__ */ import_react449.default.createElement(UiButton, {
449469
+ variant: "secondary",
449470
+ onClick: handleClose,
449471
+ disabled: isDeleting
449472
+ }, "Отмена"), /* @__PURE__ */ import_react449.default.createElement(UiButton, {
449473
+ variant: "primary",
449474
+ className: ConfirmDeleteModal_module_default.dangerButton,
449475
+ onClick: handleConfirmDelete,
449476
+ disabled: isDeleting
449477
+ }, isDeleting ? "Удаление..." : "Да, удалить"))));
449478
+ }
449479
+
449480
+ // src/pages/AdminPage/AdminPage.tsx
449481
+ var AdminDashboardPage = () => {
449482
+ const [boards, setBoards] = import_react450.useState([]);
449483
+ const [loading, setLoading] = import_react450.useState(true);
449484
+ const [error3, setError] = import_react450.useState(null);
449485
+ const { openModal: openModal2, setModalData: setModalData2 } = useUiModalContext();
449486
+ const [pagination, setPagination] = import_react450.useState({
449487
+ current: 1,
449488
+ pageSize: 10,
449489
+ total: 0
449490
+ });
449491
+ const navigate = useNavigate();
449492
+ const [searchQuery, setSearchQuery] = import_react450.useState("");
449493
+ const [searchTerm, setSearchTerm] = import_react450.useState("");
449494
+ const fetchBoardsData = import_react450.useCallback(async (page, pageSize2, query2) => {
449495
+ setLoading(true);
449496
+ setError(null);
449497
+ try {
449498
+ const response = (await exports_boards.getBoardsWithUsers(page, pageSize2, query2)).data;
449499
+ if (!response) {
449500
+ setError("Не удалось загрузить данные. Попробуйте обновить страницу.");
449501
+ return;
449502
+ }
449503
+ setBoards(response.data);
449504
+ setPagination((prev2) => ({
449505
+ ...prev2,
449506
+ total: response.total,
449507
+ current: page,
449508
+ pageSize: pageSize2
449509
+ }));
449510
+ } catch (err2) {
449511
+ setError("Не удалось загрузить данные. Попробуйте обновить страницу.");
449512
+ console.error(err2);
449513
+ } finally {
449514
+ setLoading(false);
449515
+ }
449516
+ }, []);
449517
+ import_react450.useEffect(() => {
449518
+ fetchBoardsData(pagination.current, pagination.pageSize, searchQuery);
449519
+ }, [fetchBoardsData, pagination.current, pagination.pageSize, searchQuery]);
449520
+ const handlePageChange = (newPage) => {
449521
+ if (newPage > 0 && newPage <= Math.ceil(pagination.total / pagination.pageSize)) {
449522
+ setPagination((prev2) => ({ ...prev2, current: newPage }));
449523
+ }
449524
+ };
449525
+ const handleSearch = () => {
449526
+ setPagination((prev2) => ({ ...prev2, current: 1 }));
449527
+ setSearchQuery(searchTerm);
449528
+ };
449529
+ const handleClearSearch = () => {
449530
+ setSearchTerm("");
449531
+ setSearchQuery("");
449532
+ setPagination((prev2) => ({ ...prev2, current: 1 }));
449533
+ };
449534
+ const handleDelete = (board) => {
449535
+ setModalData2({
449536
+ board,
449537
+ onSuccess: () => fetchBoardsData(pagination.current, pagination.pageSize, searchQuery)
449538
+ });
449539
+ openModal2(CONFIRM_DELETE_MODAL);
449540
+ };
449541
+ const showUsersModal = (board) => {
449542
+ setModalData2({
449543
+ board,
449544
+ onSuccess: () => fetchBoardsData(pagination.current, pagination.pageSize, searchQuery)
449545
+ });
449546
+ openModal2(MANAGE_USERS_MODAL);
449547
+ };
449548
+ const showAccessModal = (board) => {
449549
+ setModalData2({
449550
+ board,
449551
+ onSuccess: () => fetchBoardsData(pagination.current, pagination.pageSize, searchQuery)
449552
+ });
449553
+ openModal2(MANAGE_ACCESS_MODAL);
449554
+ };
449555
+ const totalPages = Math.ceil(pagination.total / pagination.pageSize);
449556
+ const handleBackBtnClick = () => {
449557
+ navigate("/");
449558
+ };
449559
+ return /* @__PURE__ */ import_react450.default.createElement("div", {
449560
+ className: AdminPage_module_default.adminDashboard
449561
+ }, /* @__PURE__ */ import_react450.default.createElement("div", {
449562
+ className: AdminPage_module_default.header
449563
+ }, /* @__PURE__ */ import_react450.default.createElement(UiButton, {
449564
+ variant: "secondary",
449565
+ className: AdminPage_module_default.backBtn,
449566
+ onClick: handleBackBtnClick
449567
+ }, /* @__PURE__ */ import_react450.default.createElement(Icon, {
449568
+ width: 24,
449569
+ height: 24,
449570
+ iconName: "BackArrow"
449571
+ })), /* @__PURE__ */ import_react450.default.createElement("h2", {
449572
+ className: AdminPage_module_default.dashboardTitle
449573
+ }, "Управление досками")), /* @__PURE__ */ import_react450.default.createElement("div", {
449574
+ className: AdminPage_module_default.searchBar
449575
+ }, /* @__PURE__ */ import_react450.default.createElement("div", {
449576
+ style: { width: "100%" }
449577
+ }, /* @__PURE__ */ import_react450.default.createElement(Input, {
449578
+ id: "admin-board-search-input",
449579
+ placeholder: "Введите ID доски для поиска",
449580
+ value: searchTerm,
449581
+ onChange: (e15) => setSearchTerm(e15.target.value)
449582
+ })), /* @__PURE__ */ import_react450.default.createElement(Button, {
449583
+ className: AdminPage_module_default.searchBtn,
449584
+ onClick: handleSearch,
449585
+ pattern: "tertiary"
449586
+ }, "Найти"), searchTerm && /* @__PURE__ */ import_react450.default.createElement(Button, {
449587
+ className: AdminPage_module_default.searchBtn,
449588
+ onClick: handleClearSearch
449589
+ }, "Очистить")), error3 && /* @__PURE__ */ import_react450.default.createElement("div", {
449590
+ className: AdminPage_module_default.errorAlert
449591
+ }, error3), /* @__PURE__ */ import_react450.default.createElement("div", {
449592
+ className: AdminPage_module_default.tableContainer
449593
+ }, /* @__PURE__ */ import_react450.default.createElement("table", {
449594
+ className: AdminPage_module_default.customTable
449595
+ }, /* @__PURE__ */ import_react450.default.createElement("thead", null, /* @__PURE__ */ import_react450.default.createElement("tr", null, /* @__PURE__ */ import_react450.default.createElement("th", null, "ID"), /* @__PURE__ */ import_react450.default.createElement("th", null, "Название"), /* @__PURE__ */ import_react450.default.createElement("th", null, "Автор"), /* @__PURE__ */ import_react450.default.createElement("th", null, "Статус"), /* @__PURE__ */ import_react450.default.createElement("th", null, "Действия"))), /* @__PURE__ */ import_react450.default.createElement("tbody", null, loading ? /* @__PURE__ */ import_react450.default.createElement("tr", null, /* @__PURE__ */ import_react450.default.createElement("td", {
449596
+ colSpan: 5,
449597
+ className: AdminPage_module_default.loadingCell
449598
+ }, "Загрузка...")) : boards.length > 0 ? boards.map((board) => /* @__PURE__ */ import_react450.default.createElement("tr", {
449599
+ key: board.uuid
449600
+ }, /* @__PURE__ */ import_react450.default.createElement("td", {
449601
+ "data-label": "ID"
449602
+ }, board.uuid), /* @__PURE__ */ import_react450.default.createElement("td", {
449603
+ "data-label": "Название"
449604
+ }, board.title), /* @__PURE__ */ import_react450.default.createElement("td", {
449605
+ "data-label": "Автор"
449606
+ }, board.author?.email || "N/A"), /* @__PURE__ */ import_react450.default.createElement("td", {
449607
+ "data-label": "Статус"
449608
+ }, /* @__PURE__ */ import_react450.default.createElement("span", {
449609
+ onClick: () => showAccessModal(board),
449610
+ className: clsx_default(AdminPage_module_default.statusTag, board.isPublic ? AdminPage_module_default.statusPublic : AdminPage_module_default.statusPrivate)
449611
+ }, board.isPublic ? "Публичная" : "Приватная")), /* @__PURE__ */ import_react450.default.createElement("td", {
449612
+ "data-label": "Действия"
449613
+ }, /* @__PURE__ */ import_react450.default.createElement("div", {
449614
+ className: AdminPage_module_default.actionButtons
449615
+ }, /* @__PURE__ */ import_react450.default.createElement(Button, {
449616
+ pattern: "quaternary",
449617
+ onClick: () => showUsersModal(board)
449618
+ }, "Пользователи"), /* @__PURE__ */ import_react450.default.createElement(Button, {
449619
+ onClick: () => handleDelete(board),
449620
+ pattern: "primary"
449621
+ }, "Удалить"))))) : /* @__PURE__ */ import_react450.default.createElement("tr", null, /* @__PURE__ */ import_react450.default.createElement("td", {
449622
+ colSpan: 5,
449623
+ className: AdminPage_module_default.noDataCell
449624
+ }, "Данные не найдены"))))), !loading && pagination.total > 0 && /* @__PURE__ */ import_react450.default.createElement("div", {
449625
+ className: AdminPage_module_default.pagination
449626
+ }, /* @__PURE__ */ import_react450.default.createElement(Button, {
449627
+ className: AdminPage_module_default.searchBtn,
449628
+ onClick: () => handlePageChange(pagination.current - 1),
449629
+ disabled: pagination.current === 1
449630
+ }, "Назад"), /* @__PURE__ */ import_react450.default.createElement("span", null, "Страница ", pagination.current, " из ", totalPages), /* @__PURE__ */ import_react450.default.createElement(Button, {
449631
+ className: AdminPage_module_default.searchBtn,
449632
+ onClick: () => handlePageChange(pagination.current + 1),
449633
+ disabled: pagination.current === totalPages
449634
+ }, "Вперед")), /* @__PURE__ */ import_react450.default.createElement(UiModalBackground, null, /* @__PURE__ */ import_react450.default.createElement(ManageAccessModal, null), /* @__PURE__ */ import_react450.default.createElement(ManageUsersModal, null), /* @__PURE__ */ import_react450.default.createElement(ConfirmDeleteModal, null)));
449635
+ };
449636
+
449637
+ // src/entities/account/RouterRolesGuard.tsx
449638
+ var import_react451 = __toESM(require_react(), 1);
449639
+ function RouterRolesGuard({ allowedRoles }) {
449640
+ const account = useAccount2();
449641
+ if (!account.isInitialized) {
449642
+ return null;
449643
+ }
449644
+ const userRole = account.tokenData?.role;
449645
+ if (userRole && allowedRoles.includes(userRole)) {
449646
+ return /* @__PURE__ */ import_react451.default.createElement(Outlet, null);
449647
+ } else {
449648
+ return /* @__PURE__ */ import_react451.default.createElement(Navigate2, {
449649
+ to: "/",
449650
+ replace: true
449651
+ });
449652
+ }
449653
+ }
449654
+
449655
+ // src/App/router.tsx
449069
449656
  function getRender(app) {
449070
449657
  const router = createBrowserRouter([
449071
449658
  {
449072
- element: /* @__PURE__ */ import_react447.default.createElement(AppLayout, {
449659
+ element: /* @__PURE__ */ import_react452.default.createElement(AppLayout, {
449073
449660
  app
449074
449661
  }),
449075
449662
  children: [
449076
- { path: "/", element: /* @__PURE__ */ import_react447.default.createElement(Navigate2, {
449663
+ { path: "/", element: /* @__PURE__ */ import_react452.default.createElement(Navigate2, {
449077
449664
  to: "/boards/blank"
449078
449665
  }) },
449079
449666
  {
449080
449667
  path: "/auth",
449081
- element: /* @__PURE__ */ import_react447.default.createElement(AuthLayout, {
449668
+ element: /* @__PURE__ */ import_react452.default.createElement(AuthLayout, {
449082
449669
  showPolicies: true
449083
449670
  }),
449084
449671
  children: [
449085
449672
  {
449086
- element: /* @__PURE__ */ import_react447.default.createElement(UnauthGuard, null),
449673
+ element: /* @__PURE__ */ import_react452.default.createElement(UnauthGuard, null),
449087
449674
  children: [
449088
- { path: "sign-up", element: /* @__PURE__ */ import_react447.default.createElement(SignupPage, null) },
449089
- { path: "sign-in", element: /* @__PURE__ */ import_react447.default.createElement(SigninPage, null) },
449090
- { path: "verify", element: /* @__PURE__ */ import_react447.default.createElement(VerifyMailPage, null) },
449091
- { path: "restore-password", element: /* @__PURE__ */ import_react447.default.createElement(RestorePasswordPage, null) },
449092
- { path: "forgot-password", element: /* @__PURE__ */ import_react447.default.createElement(ForgotPasswordPage, null) }
449675
+ { path: "sign-up", element: /* @__PURE__ */ import_react452.default.createElement(SignupPage, null) },
449676
+ { path: "sign-in", element: /* @__PURE__ */ import_react452.default.createElement(SigninPage, null) },
449677
+ { path: "verify", element: /* @__PURE__ */ import_react452.default.createElement(VerifyMailPage, null) },
449678
+ { path: "restore-password", element: /* @__PURE__ */ import_react452.default.createElement(RestorePasswordPage, null) },
449679
+ { path: "forgot-password", element: /* @__PURE__ */ import_react452.default.createElement(ForgotPasswordPage, null) }
449093
449680
  ]
449094
449681
  }
449095
449682
  ]
449096
449683
  },
449097
449684
  {
449098
449685
  path: "/bind-email",
449099
- element: /* @__PURE__ */ import_react447.default.createElement(AuthLayout, null),
449686
+ element: /* @__PURE__ */ import_react452.default.createElement(AuthLayout, null),
449100
449687
  children: [
449101
- { path: "add-email", element: /* @__PURE__ */ import_react447.default.createElement(AddEmailPage, null) },
449102
- { path: "verify", element: /* @__PURE__ */ import_react447.default.createElement(BindEmailPage, null) }
449688
+ { path: "add-email", element: /* @__PURE__ */ import_react452.default.createElement(AddEmailPage, null) },
449689
+ { path: "verify", element: /* @__PURE__ */ import_react452.default.createElement(BindEmailPage, null) }
449103
449690
  ]
449104
449691
  },
449105
- { path: "/welcome", element: /* @__PURE__ */ import_react447.default.createElement(WelcomePage, null) },
449106
- { path: "/boards/:boardId?", element: /* @__PURE__ */ import_react447.default.createElement(BoardPage, null) },
449107
- { path: "/selectBoard", element: /* @__PURE__ */ import_react447.default.createElement(SelectBoardPage, null) },
449108
- { path: "/test-wheel", element: /* @__PURE__ */ import_react447.default.createElement(WheelEventLoggerPage, null) },
449109
- { path: "/snapshots/:uid?", element: /* @__PURE__ */ import_react447.default.createElement(HTMLSnapshot_default, null) }
449692
+ {
449693
+ element: /* @__PURE__ */ import_react452.default.createElement(RouterRolesGuard, {
449694
+ allowedRoles: ["ADMIN" /* ADMIN */]
449695
+ }),
449696
+ children: [{ path: "/admin", element: /* @__PURE__ */ import_react452.default.createElement(AdminDashboardPage, null) }]
449697
+ },
449698
+ { path: "/welcome", element: /* @__PURE__ */ import_react452.default.createElement(WelcomePage, null) },
449699
+ { path: "/boards/:boardId?", element: /* @__PURE__ */ import_react452.default.createElement(BoardPage, null) },
449700
+ { path: "/selectBoard", element: /* @__PURE__ */ import_react452.default.createElement(SelectBoardPage, null) },
449701
+ { path: "/test-wheel", element: /* @__PURE__ */ import_react452.default.createElement(WheelEventLoggerPage, null) },
449702
+ { path: "/snapshots/:uid?", element: /* @__PURE__ */ import_react452.default.createElement(HTMLSnapshot_default, null) }
449110
449703
  ]
449111
449704
  }
449112
449705
  ]);
@@ -449120,7 +449713,7 @@ function getRender(app) {
449120
449713
  if (!root3) {
449121
449714
  root3 = import_client2.createRoot(container);
449122
449715
  }
449123
- root3.render(/* @__PURE__ */ import_react447.default.createElement(RouterProvider, {
449716
+ root3.render(/* @__PURE__ */ import_react452.default.createElement(RouterProvider, {
449124
449717
  router
449125
449718
  }));
449126
449719
  },
@@ -449137,9 +449730,9 @@ function getLocalRender(app) {
449137
449730
  if (!root3) {
449138
449731
  root3 = import_client2.createRoot(container);
449139
449732
  }
449140
- root3.render(/* @__PURE__ */ import_react447.default.createElement(LocalAppLayout, {
449733
+ root3.render(/* @__PURE__ */ import_react452.default.createElement(LocalAppLayout, {
449141
449734
  app
449142
- }, /* @__PURE__ */ import_react447.default.createElement(LocalSidePanelContextProvider, null, /* @__PURE__ */ import_react447.default.createElement(LocalAppView, null))));
449735
+ }, /* @__PURE__ */ import_react452.default.createElement(LocalSidePanelContextProvider, null, /* @__PURE__ */ import_react452.default.createElement(LocalAppView, null))));
449143
449736
  };
449144
449737
  }
449145
449738