{"version":3,"file":"app-a9cd6d04.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-durations-or-points-table/access-code-statistics-durations-or-points-table.html","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-details-table/access-code-statistics-users-and-sessions-details-table.html","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-overview/access-code-statistics-users-and-sessions-overview.html","webpack://lernplattform-admin-frontend/./src/resources/elements/additional-info-form/additional-info-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/ai-questions-form/ai-questions-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/alert-message/alert-message.html","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-durations-or-points-table/access-code-statistics-durations-or-points-table.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-details-table/access-code-statistics-users-and-sessions-details-table.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-overview/access-code-statistics-users-and-sessions-overview.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/access-code-statistics/index.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/additional-info-form/additional-info-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/ai-questions-form/ai-questions-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/alert-message/alert-message.ts"],"sourcesContent":["// Module\nvar code = \"<template> <custom-table columns.to-view=\\\"tableColumns\\\" extendable.to-view=\\\"true\\\" table-id=\\\"access-code-statistics-durations-or-points\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\"></custom-table> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <custom-table columns.to-view=\\\"tableColumns\\\" extendable.to-view=\\\"true\\\" table-id=\\\"access-code-statistics-users-and-sessions\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\"></custom-table> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div repeat.for=\\\"metric of metrics\\\" class=\\\"row mb-2\\\"> <span class=\\\"form-label col-md-3 mb-0\\\" t=\\\"pages.statisticsAccessCodes.resultsOverview.${metric.key}\\\"></span> <span class=\\\"col-md-4 align-content-center\\\">${metric.value}</span> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <audio-select-form t=\\\"[title]elements.additionalInfoForm.correctAnswerInfoAudio\\\" course-id.to-view=\\\"courseId\\\" audio-file-name.to-view=\\\"block.correctAnswerInfoAudioUrl\\\" audio-file-title.to-view=\\\"block.correctAnswerInfoAudioTitle\\\" audio-id.two-way=\\\"block.correctAnswerInfoAudioId\\\" audio-url.to-view=\\\"block.correctAnswerInfoAudioUrl\\\"></audio-select-form> <audio-select-form t=\\\"[title]elements.additionalInfoForm.incorrectAnswerInfoAudio\\\" course-id.to-view=\\\"courseId\\\" audio-file-name.to-view=\\\"block.incorrectAnswerInfoAudioUrl\\\" audio-file-title.to-view=\\\"block.incorrectAnswerInfoAudioTitle\\\" audio-id.two-way=\\\"block.incorrectAnswerInfoAudioId\\\" audio-url.to-view=\\\"block.incorrectAnswerInfoAudioUrl\\\"></audio-select-form> <picture-select-form t=\\\"[title]elements.additionalInfoForm.correctAnswerInfoPicture\\\" course-id.to-view=\\\"courseId\\\" picture-id.two-way=\\\"block.correctAnswerInfoPictureId\\\" picture-title.to-view=\\\"block.correctAnswerInfoPictureTitle\\\" picture.two-way=\\\"block.correctAnswerInfoPicture\\\"></picture-select-form> <picture-select-form t=\\\"[title]elements.additionalInfoForm.incorrectAnswerInfoPicture\\\" course-id.to-view=\\\"courseId\\\" picture-id.two-way=\\\"block.incorrectAnswerInfoPictureId\\\" picture-title.to-view=\\\"block.incorrectAnswerInfoPictureTitle\\\" picture.two-way=\\\"block.incorrectAnswerInfoPicture\\\"></picture-select-form> <div class=\\\"row\\\"> <div class=\\\"col-8\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.additionalInfoForm.correctAnswerInfoText\\\"></label> <textarea value.two-way=\\\"block.correctAnswerInfoText\\\" class=\\\"form-control additional-info-form__textarea\\\"></textarea> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-8\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.additionalInfoForm.incorrectAnswerInfoText\\\"></label> <textarea value.two-way=\\\"block.incorrectAnswerInfoText\\\" class=\\\"form-control additional-info-form__textarea\\\"></textarea> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"row row-cards row-deck ai-questions-form\\\"> <div class=\\\"col-12\\\"> <div class=\\\"card\\\"> <div class=\\\"card-body\\\"> <template if.to-view=\\\"!generatedQuestions.length\\\"> <p if.to-view=\\\"!actionInProgress\\\" t=\\\"elements.questionsForm.noQuestionsGenerated\\\"></p> <self-writing if.to-view=\\\"actionInProgress\\\" t=\\\"[write]elements.questionsForm.generating\\\" thinking.to-view=\\\"true\\\"></self-writing> </template> <div repeat.for=\\\"question of generatedQuestions\\\" class=\\\"ai-questions-form__question ${questionRegenerating[$index] ? 'ai-questions-form__question--regenerating' : ''}\\\"> <self-writing thinking.to-view=\\\"questionRegenerating[$index]\\\" disabled.to-view=\\\"questionEdited[$index]\\\" cps.to-view=\\\"200\\\"> <div class=\\\"d-flex\\\"> <button class=\\\"btn btn-link text-left\\\" click.trigger=\\\"showQuestionPreview(question)\\\">${question.text}</button> <button-standard class=\\\"ml-auto\\\" btn-size=\\\"tiny\\\" click.delegate=\\\"regenerateQuestion($index)\\\" btn-color=\\\"none\\\" disabled.to-view=\\\"actionInProgress\\\" icon-name=\\\"System/Tabler/Refresh\\\"></button-standard> <button-standard btn-size=\\\"tiny\\\" click.delegate=\\\"editQuestion(question, $index)\\\" btn-color=\\\"none\\\" disabled.to-view=\\\"actionInProgress\\\" icon-name=\\\"System/Tabler/Edit\\\"></button-standard> </div> <ul repeat.for=\\\"answer of question.answers\\\"> <li repeat.for=\\\"option of getAnswerOptions(answer)\\\" class=\\\"ai-questions-form__answer ai-questions-form__answer--${option.correct ? 'correct' : 'wrong'}\\\">${option.text}</li> </ul> </self-writing> </div> </div> <div class=\\\"card-footer text-right d-flex\\\"> <div if.to-view=\\\"availablePages.length\\\" class=\\\"d-flex align-items-center ml-auto flex-grow-1\\\"> <h6 class=\\\"mb-0 mr-2\\\" t=\\\"globals.page\\\"></h6> <select class=\\\"custom-select\\\" change.delegate=\\\"changePage()\\\" value.two-way=\\\"selectedPage\\\"> <option repeat.for=\\\"page of availablePages\\\" model.bind=\\\"page\\\">${page.chapterPrefix} ${page.label}</option> </select> </div> <button-standard if.to-view=\\\"isProvider\\\" class=\\\"ml-2 flex-shrink-0\\\" click.delegate=\\\"generateQuestions()\\\" disabled.to-view=\\\"actionInProgress\\\" t=\\\"[btnText]elements.questionsForm.generateQuestions\\\" icon-name=\\\"System/Ai\\\" btn-color=\\\"primary\\\"></button-standard> </div> </div> <alert-message if.to-view=\\\"errorTk\\\" message.to-view=\\\"{ tk: errorTk }\\\" message-style=\\\"alert-danger\\\"></alert-message> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"alert alert-message ${messageStyle}\\\" role=\\\"alert\\\"> <x-icon if.to-view=\\\"showIcon && iconName\\\" class=\\\"alert-message__icon\\\" icon-type.to-view=\\\"`custom`\\\" size.to-view=\\\"`unspecified`\\\" icon-name.to-view=\\\"iconName\\\"></x-icon> <span t=\\\"${message.html ? '[html]' : '[text]'}${message.tk}\\\" t-params.to-view=\\\"message.tkParams\\\"></span> </template>\";\n// Exports\nexport default code;","import { autoinject, bindable } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { IPaginatedDto } from 'common/dto/filter/filter.interface';\nimport { \n  IAccessCodeStatisticsDurationsOrPointsResponseDto,\n} from 'common/dto/statistics/access-code/access-code.statistics.interface';\nimport { AccessCodeStatisticsDurationsOrPointsType } from 'common/enum/statistics.enum';\nimport { CustomTableCell } from 'resources/elements/custom-table/custom-table-cell/custom-table-cell';\nimport { IColumnDefinition } from 'resources/elements/custom-table/custom-table-interfaces';\nimport { StringUtils } from 'common/utils/StringUtils';\n\n/**\n * This table can work dynamically for different column sets. For this purpose,\n * the following would be the desired TableRow type to feed into the tableColumns definition:\n * type TableRow = ITableRowDurations & (ITableRowIdentifiersUser | ITableRowIdentifiersInterval);\n * But the table system doesn't like this ambivalence, so we use a little bit less \n * precise workaround type:\n */\ntype TableRowWorkaround =  ITableRowDurations \n  & ITableRowIdentifiersUser \n  & ITableRowIdentifiersInterval;\n\ninterface ITableRowIdentifiersUser {\n  userId: string;\n  firstname: string;\n  lastname: string;\n  nickname: string;\n  birthdate: string;\n  state: string;\n}\n\ninterface ITableRowIdentifiersInterval {\n  interval: string;\n}\n\ninterface ITableRowDurations {\n  averageLearningDuration: string;\n  averageTrainingDuration: string;\n  averageTestexamDuration: string;\n  averageGamesDuration: string;\n  totalLearningDuration: string;\n  totalTrainingDuration: string;\n  totalTestexamDuration: string;\n  totalGamesDuration: string;\n  totalDuration: string;\n}\n\n@autoinject()\nexport class AccessCodeStatisticsDurationsOrPointsTable {\n  @bindable() public statistics: IAccessCodeStatisticsDurationsOrPointsResponseDto | null = null;\n  @bindable() public byMode = AccessCodeStatisticsDurationsOrPointsType.ByIntervals;\n  private tableRefreshVersion: number = 0;\n  private tableColumns: Array<IColumnDefinition<CustomTableCell<TableRowWorkaround>>> = [];\n  private tableContent: IPaginatedDto<TableRowWorkaround> | null = null;\n  private modeByUsers = false;\n\n  constructor(\n    private i18n: I18N,\n  ) { }\n\n  protected attached(): void {\n    this.prepareTableData();\n  }\n\n  private statisticsChanged(): void {\n    this.prepareTableData();\n    this.tableRefreshVersion++;\n  }\n\n  private prepareTableData(): void {\n    if(!this.statistics) return;\n    this.modeByUsers = this.byMode === AccessCodeStatisticsDurationsOrPointsType.ByUsers;     \n\n    const tableRows: TableRowWorkaround[] = this.statistics.rows.map(row => {\n      const durations: ITableRowDurations = {\n        averageLearningDuration: this.convertToMinutesString(row.averages.learning),\n        averageTrainingDuration: this.convertToMinutesString(row.averages.training),\n        averageTestexamDuration: this.convertToMinutesString(row.averages.testexam),\n        averageGamesDuration: this.convertToMinutesString(row.averages.games),\n        totalLearningDuration: this.convertToMinutesString(row.totals.learning),\n        totalTrainingDuration: this.convertToMinutesString(row.totals.training),\n        totalTestexamDuration: this.convertToMinutesString(row.totals.testexam),\n        totalGamesDuration: this.convertToMinutesString(row.totals.games),\n        totalDuration: this.convertToMinutesString(row.total),\n      };\n\n      return {\n        ...durations,\n        interval: row.interval ?? '',\n        userId: row.user?.id.toFixed(0) ?? '',\n        firstname: row.user?.firstname ?? '',\n        lastname: row.user?.lastname ?? '',\n        nickname: row.user?.nickname ?? '',\n        birthdate: row.user?.birthdate && (typeof row.user?.birthdate === 'string') \n          ? new Date(row.user.birthdate as string).toLocaleDateString('de') : '',\n        state: row.user?.address.state ?? '',\n      };\n    });\n\n    this.tableContent = {\n      rows: tableRows,\n      count: tableRows.length,\n    };\n\n    this.tableColumns = [\n      ...!this.modeByUsers ? [{\n        id: 'interval',\n        nameTk: 'pages.statisticsAccessCodes.interval',\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.interval ?? '',\n        },\n      }] : [\n        {\n          id: 'userId',\n          nameTk: 'pages.statisticsAccessCodes.user.id',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.userId ?? '',\n          },\n        },\n        {\n          id: 'userFirstname',\n          nameTk: 'pages.statisticsAccessCodes.user.firstname',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.firstname ?? '',\n          },\n        },\n        {\n          id: 'userLastname',\n          nameTk: 'pages.statisticsAccessCodes.user.lastname',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.lastname ?? '',\n          },\n        },\n        {\n          id: 'userNickname',\n          nameTk: 'pages.statisticsAccessCodes.user.nickname',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.nickname ?? '',\n          },\n        },\n        {\n          id: 'userBirthdate',\n          nameTk: 'pages.statisticsAccessCodes.user.birthdate',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.birthdate ?? '',\n          },\n        },\n        {\n          id: 'userAddressState',\n          nameTk: 'pages.statisticsAccessCodes.user.state',\n          cellViewModel: CustomTableCell,\n          cellOptions: {\n            transformer: (tR: TableRowWorkaround) => tR.state ?? '',\n          },\n        },\n      ],\n      {\n        id: 'averageLearningDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.average')} ${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.daily')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.learning')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.averageLearningDuration,\n        },\n      },\n      {\n        id: 'averageTrainingDuration',        \n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.average')} ${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.daily')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.training')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.averageTrainingDuration,\n        },\n      },\n      {\n        id: 'averageTestexamDuration',        \n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.average')} ${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.daily')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.testexam')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.averageTestexamDuration,\n        },\n      },\n      {\n        id: 'averageGamesDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.average')} ${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.daily')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.games')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.averageGamesDuration,\n        },\n      },\n      {\n        id: 'totalLearningDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.total')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.learning')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.totalLearningDuration,\n        },\n      },\n      {\n        id: 'totalTrainingDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.total')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.training')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.totalTrainingDuration,\n        },\n      },\n      {\n        id: 'totalTestexamDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.total')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.testexam')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.totalTestexamDuration,\n        },\n      },\n      {\n        id: 'totalGamesDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.total')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.games')}-${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.totalGamesDuration,\n        },\n      },\n      {\n        id: 'totalDuration',\n        nameTk: '',\n        nameHtml: `${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.total')}<br>${this.i18n\n          .tr('pages.statisticsAccessCodes.duration.duration')}`,\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: TableRowWorkaround) => tR.totalDuration,\n        },\n      },\n    ];\n  }\n\n  private convertToMinutesString(duration: number): string {\n    return `${StringUtils.formatNumberGrouped(Number(duration.toFixed(1)))} ${this.i18n\n      .tr('pages.statisticsAccessCodes.minutes')}`;\n  }\n    \n  private fetchTableData(limit: number, offset: number): { total: number; data: TableRowWorkaround[] } {\n    if(!this.tableContent?.rows) return { total: 0, data: [] };\n    return {\n      total: this.tableContent.rows.length,\n      data: this.tableContent.rows.slice(offset, offset + limit),\n    };\n  }   \n}\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { IPaginatedDto } from 'common/dto/filter/filter.interface';\nimport {\n  IAccessCodeStatisticsUsersAndSessionsDetailsResponseDto,\n} from 'common/dto/statistics/access-code/access-code.statistics.interface';\nimport { StringUtils } from 'common/utils/StringUtils';\nimport { CustomTableCell } from 'resources/elements/custom-table/custom-table-cell/custom-table-cell';\nimport { IColumnDefinition } from 'resources/elements/custom-table/custom-table-interfaces';\n\ninterface IDynamicTableRow {\n  interval: string;\n  [key: string]: string;\n}\n\n@autoinject()\nexport class AccessCodeStatisticsUsersAndSessionsDetailsTable {\n  @bindable() public statistics: IAccessCodeStatisticsUsersAndSessionsDetailsResponseDto | null = null;\n  private tableRefreshVersion: number = 0;\n  private tableColumns: Array<IColumnDefinition<CustomTableCell<IDynamicTableRow>>> = [];\n  private tableContent: IPaginatedDto<IDynamicTableRow> | null = null;\n\n  constructor(\n    private i18n: I18N,\n  ) { }\n\n  protected attached(): void {\n    this.prepareTableData();\n  }\n\n  private statisticsChanged(): void {\n    this.prepareTableData();\n    this.tableRefreshVersion++;\n  }\n\n  private prepareTableData(): void {\n    if(!this.statistics) return;\n\n    const tableRows: IDynamicTableRow[] = this.statistics.rows.map(row => ({\n      interval: row.interval,\n      ...row.activeUsers.reduce((acc, value, index) => {\n        acc[`activeUsersIndex${index + 1}`] = StringUtils.formatNumberGrouped(value);\n        return acc;\n      }, {} as Record<string, string>),\n      ...row.sessions.reduce((acc, value, index) => {\n        acc[`sessionsIndex${index + 1}`] = StringUtils.formatNumberGrouped(value);\n        return acc;\n      }, {} as Record<string, string>),\n    }));\n    this.tableContent = {\n      rows: tableRows,\n      count: tableRows.length,\n    };    \n\n    this.tableColumns = [\n      {\n        id: 'interval',\n        nameTk: 'pages.statisticsAccessCodes.interval',\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: tR => tR.interval,\n        },\n      },    \n      ...this.statistics.headers.map((header, index) => ({\n        id: `header-activeUsers-${index + 1}`,\n        nameHtml: `${this.i18n.tr('pages.statisticsAccessCodes.activeUsers')}<br>${header.identifier}`,\n        nameTk: `${this.i18n.tr('pages.statisticsAccessCodes.activeUsers')} ${header.identifier}`, // fallback\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: { [x: string]: any }) => tR[`activeUsersIndex${index + 1}`] ?? '-'\n        },\n      })),\n      ...this.statistics.headers.map((header, index) => ({\n        id: `header-sessions-${index + 1}`,\n        nameHtml: `${this.i18n.tr('pages.statisticsAccessCodes.sessions')}<br>${header.identifier}`,\n        nameTk: `${this.i18n.tr('pages.statisticsAccessCodes.sessions')} ${header.identifier}`, // fallback\n        cellViewModel: CustomTableCell,\n        cellOptions: {\n          transformer: (tR: { [x: string]: any }) => tR[`sessionsIndex${index + 1}`] ?? '-'\n        },\n      })),\n    ];\n  }\n    \n  private fetchTableData(limit: number, offset: number): { total: number; data: IDynamicTableRow[] } {\n    if(!this.tableContent?.rows) return { total: 0, data: [] };\n    return {\n      total: this.tableContent.rows.length,\n      data: this.tableContent.rows.slice(offset, offset + limit),\n    };\n  }   \n}\n","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport {\n  IAccessCodeStatisticsUsersAndSessionsOverviewResponseDto,\n} from 'common/dto/statistics/access-code/access-code.statistics.interface';\nimport { StringUtils } from 'common/utils/StringUtils';\n\n@autoinject()\nexport class AccessCodeStatisticsUsersAndSessionsOverview {\n  @bindable() public statistics: IAccessCodeStatisticsUsersAndSessionsOverviewResponseDto | null = null;\n\n  constructor(\n    private i18n: I18N,\n  ) { }\n\n  @computedFrom('statistics')\n  private get metrics(): Array<{ key: string; value: string }> {\n    if(!this.statistics) return [];\n\n    return [\n      { \n        key: 'averageDailyActiveUsers', \n        value: StringUtils.formatNumberGrouped(Number(this.statistics.averageDailyActiveUsers.toFixed(0))),\n      },\n      { \n        key: 'totalActiveUserDays',\n        value: StringUtils.formatNumberGrouped(Number(this.statistics.totalActiveUserDays.toFixed(0))),\n      },\n      { \n        key: 'totalSessionsCount',\n        value: StringUtils.formatNumberGrouped(Number(this.statistics.totalSessionsCount.toFixed(0))),\n      },\n      { \n        key: 'averageSessionsPerDay',\n        value: StringUtils.formatNumberGrouped(Number(this.statistics.averageSessionsPerDay.toFixed(0))),\n      },\n      { \n        key: 'averageSessionLengthMinutes',\n        value: `${StringUtils.formatNumberGrouped(Number(this.statistics.averageSessionLengthMinutes.toFixed(1)))} ${this\n          .i18n.tr('pages.statisticsAccessCodes.minutes')}`,\n      },\n    ];\n  }\n}\n","import { PLATFORM } from 'aurelia-pal';\nimport { FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('resources/elements/access-code-statistics/access-code-statistics-durations-or-points-table/access-code-statistics-durations-or-points-table'));\n  config.globalResources(PLATFORM.moduleName('resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-overview/access-code-statistics-users-and-sessions-overview'));\n  config.globalResources(PLATFORM.moduleName('resources/elements/access-code-statistics/access-code-statistics-users-and-sessions-details-table/access-code-statistics-users-and-sessions-details-table'));\n}\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { IBlockEditResponseDto } from 'common/dto/course/management/course.management.interface';\n\n@autoinject\nexport class AdditionalInfoForm {\n  @bindable public courseId: number | null = null;\n  @bindable public block: IBlockEditResponseDto<string> | null = null;\n}\n","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { selectState } from 'common/aurelia-decorators/select-state';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { IAnswerDto } from 'common/dto/course/content/answer.interface';\nimport { QuestionType } from 'common/dto/course/content/course.types';\nimport { ICoursePageDto, ILabeledCoursePageDto } from 'common/dto/course/content/page.interface';\nimport { IQuestionDto } from 'common/dto/course/content/question.interface';\nimport { ErrorType } from 'common/enum/errortype.enum';\nimport { RoleName } from 'common/enum/role.enums';\nimport { isPresentationSelectorCreator } from 'common/store/selectors/content.context.selectors';\nimport { CourseUtils } from 'common/utils/CourseUtils';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { ToastService } from 'services/ToastService';\nimport { QuestionsApiService } from '../../../services/api/QuestionsApiService';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { IState } from '../../../store/state';\nimport { MediaType } from '../../dialogs/edit-question-dialog/edit-question-dialog';\n\n@autoinject()\nexport class AiQuestionsForm {\n  @bindable() public questionIds: number[] = [];\n  @bindable() public courseId: number | null = null;\n  @bindable() contextIdentifier = '';\n  @selectState(AiQuestionsForm, isPresentationSelectorCreator, ['contextIdentifier']) private isPresentation?: boolean | null;\n\n  private generatedQuestions: IQuestionDto[] | null = null;\n\n  private generationInProgress = false;\n  private questionEdited: boolean[] = [];\n  private questionRegenerating: boolean[] = [];\n  private errorTk: string | null = null;\n\n  private availablePages: Array<ILabeledCoursePageDto> = [];\n  private selectedPageId: number | null = null;\n  private selectedPage: ICoursePageDto | null = null;\n\n  private isProvider: boolean = false;\n\n  constructor(\n    private questionsApi: QuestionsApiService,\n    private dialogService: CustomDialogService,\n    private storeService: StoreService<IState>,\n    private toastService: ToastService,\n  ) { }\n\n  protected attached(): void {\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.currentRole?.role === RoleName.Provider,\n      state => state.courseContentById[this.courseId!]\n    ], (_, isProvider, course) => {\n      this.isProvider = isProvider;\n      this.availablePages = course ? CourseUtils.getFlatPageList(course) : [];\n      this.selectedPageId = this.availablePages[0].id;\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  private changePage(): void {\n    this.selectedPageId = this.selectedPage?.id ?? null;\n  }\n\n  private async generateQuestions(): Promise<void> {\n    await this.withGenerationInProgressLock(async () => {\n      if(!this.selectedPageId) return;\n      // regenerating all questions\n      this.questionRegenerating = this.generatedQuestions?.map(() => true) ?? [];\n\n      const questions = await this.questionsApi.generateQuestionsFromContent(this.selectedPageId, 4);\n\n      this.questionEdited = [];\n      this.generatedQuestions = questions;\n    });\n  }\n\n  private async regenerateQuestion(index: number): Promise<void> {\n    await this.withGenerationInProgressLock(async () => {\n      if(!this.selectedPageId || !this.generatedQuestions?.[index]) return;\n\n      // regenerating only the question of the given index\n      this.questionRegenerating = this.generatedQuestions?.map((_, i) => i === index) ?? [];\n\n      const [question] = await this.questionsApi.generateQuestionsFromContent(this.selectedPageId, 1);\n\n      this.questionEdited[index] = false;\n      this.generatedQuestions.splice(index, 1, question);\n    });\n  }\n\n  private async editQuestion(dto: IQuestionDto, index: number): Promise<void> {\n    if(this.generationInProgress || !this.courseId) return;\n\n    const question = await this.dialogService.showEditQuestionDialog({\n      courseId: this.courseId,\n      questionId: undefined,\n      floatingDto: dto,\n      dialogService: this.dialogService,\n      allowedQuestionTypes: [QuestionType.MC, QuestionType.SC],\n      allowedAnswerMediaTypes: [MediaType.Text],\n      allowedQuestionMediaTypes: [MediaType.Text],\n    });\n    if(!question) return;\n\n    this.questionEdited[index] = true;\n    this.generatedQuestions?.splice(index, 1, question);\n  }\n\n  private async withGenerationInProgressLock(callback: () => Promise<void>): Promise<void> {\n    if(this.generationInProgress) return;\n    this.generationInProgress = true;\n    this.errorTk = null;\n\n    try {\n      await callback();\n    } catch(e) {\n      LogUtils.exception(e);\n      this.errorTk = this.getErrorMessageTk(e.message);\n    } finally {\n      this.generationInProgress = false;\n      this.questionRegenerating = [];\n    }\n  }\n\n  private getErrorMessageTk(message: string): string {\n    switch(message) {\n      case ErrorType.AI_CONTENT_POLICY_VIOLATION: return 'elements.questionsForm.errors.aiContentPolicyViolation';\n      case ErrorType.AI_INSUFFICIENT_INFORMATION: return 'elements.questionsForm.errors.aiInsufficientInformation';\n      case ErrorType.AI_PROMPT_TOO_LONG: return 'elements.questionsForm.errors.aiPromptTooLong';\n      case ErrorType.AI_RESPONSE_FORMAT_ERROR: return 'elements.questionsForm.errors.aiResponseFormat';\n      case ErrorType.AI_TOO_MANY_REQUESTS: return 'elements.questionsForm.errors.aiTooManyRequests';\n      default: return 'elements.questionsForm.errors.unknownAiError';\n    }\n  }\n\n  @computedFrom('generationInProgress')\n  private get actionInProgress(): boolean {\n    return this.generationInProgress;\n  }\n\n  private getAnswerOptions(answer: IAnswerDto): IAnswerOption[] {\n    return [\n      { text: answer.text1, correct: answer.correct1 },\n      { text: answer.text2, correct: answer.correct2 },\n      { text: answer.text3, correct: answer.correct3 },\n      { text: answer.text4, correct: answer.correct4 },\n    ];\n  }\n\n  private showQuestionPreview(question: IQuestionDto): void {\n    this.dialogService.showQuestionPreview(question);\n  }\n\n  /**\n   * To be called from outside\n   */\n  public async saveQuestions(): Promise<void> {\n    if(!this.courseId || !this.generatedQuestions) return;\n    this.questionEdited = this.generatedQuestions?.map(() => true) ?? [];\n\n    try {\n      for(let questionIndex = 0; questionIndex < this.generatedQuestions.length; questionIndex++) {\n        const question = this.generatedQuestions[questionIndex];\n        const savedQuestion = await this.questionsApi.createQuestion({\n          courseId: this.courseId,\n          helpText: question.helpText ?? '',\n          learningOnly: question.learningOnly,\n          maxMediaSeenCount: question.maxMediaSeenCount,\n          text: question.text,\n          type: question.type,\n          pageId: question.pageId,\n          audioId: question.audioId,\n          importId: question.externalId,\n          pictureBlinkId: question.pictureBlink?.id,\n          pictureId: question.picture?.id,\n          videoId: question.videoId,\n        });\n        this.generatedQuestions.splice(questionIndex, 1, savedQuestion);\n\n        for(let answerIndex = 0; answerIndex < question.answers.length; answerIndex++) {\n          const answer = question.answers[answerIndex];\n          const savedAnswer = await this.questionsApi.createAnswer(savedQuestion.id, {\n            audio1Id: answer.audio1Id,\n            audio2Id: answer.audio2Id,\n            audio3Id: answer.audio3Id,\n            audio4Id: answer.audio4Id,\n            correct1: answer.correct1,\n            correct2: answer.correct2,\n            correct3: answer.correct3,\n            correct4: answer.correct4,\n            order: answerIndex,\n            picture1Id: answer.picture1?.id ?? null,\n            picture2Id: answer.picture2?.id ?? null,\n            picture3Id: answer.picture3?.id ?? null,\n            picture4Id: answer.picture4?.id ?? null,\n            text1: answer.text1,\n            text2: answer.text2,\n            text3: answer.text3,\n            text4: answer.text4,\n          });\n\n          savedQuestion.answers.splice(answerIndex, 1, savedAnswer);\n        }\n      }\n\n      this.questionIds = this.generatedQuestions.map(q => q.id);\n      this.toastService.success('pages.questions.saveQuestionSuccess');\n    } catch(e) {\n      LogUtils.exception(e);\n      this.toastService.error('pages.questions.saveQuestionError');\n      throw e;\n    }\n  }\n}\n\ninterface IAnswerOption {\n  text: string;\n  correct: boolean;\n}\n","import { bindable, computedFrom } from 'aurelia-framework';\nimport { IText } from 'common/interfaces/translations.interface';\n\nexport enum AlertMessageStyle {\n  Danger = 'alert-danger',\n  Info = 'alert-info',\n  Warning = 'alert-warning',\n  Success = 'alert-success'\n}\n\nexport class AlertMessage {\n  @bindable() public message: IText | null = null;\n  @bindable() public messageStyle: AlertMessageStyle = AlertMessageStyle.Info;\n  @bindable() public showIcon: boolean = false;\n\n  @computedFrom('messageStyle')\n  private get iconName(): string | null {\n    switch(this.messageStyle) {\n      case AlertMessageStyle.Danger:\n        return 'System/Tabler/Alert-Triangle';\n    }\n    return null;\n  }\n}"],"names":[],"sourceRoot":""}