analytica-frontend-lib 1.1.90 → 1.1.92

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.
package/dist/index.mjs CHANGED
@@ -8331,7 +8331,6 @@ var DownloadButton = ({
8331
8331
  await new Promise((resolve) => setTimeout(resolve, 200));
8332
8332
  }
8333
8333
  } catch (error) {
8334
- console.error(`Erro ao baixar ${item.label}:`, error);
8335
8334
  onDownloadError?.(
8336
8335
  item.type,
8337
8336
  error instanceof Error ? error : new Error(`Falha ao baixar ${item.label}`)
@@ -8557,6 +8556,7 @@ var VideoPlayer = ({
8557
8556
  const [showControls, setShowControls] = useState14(true);
8558
8557
  const [hasCompleted, setHasCompleted] = useState14(false);
8559
8558
  const [showCaptions, setShowCaptions] = useState14(false);
8559
+ const [subtitlesValidation, setSubtitlesValidation] = useState14("idle");
8560
8560
  useEffect15(() => {
8561
8561
  setHasCompleted(false);
8562
8562
  }, [src]);
@@ -8842,11 +8842,12 @@ var VideoPlayer = ({
8842
8842
  setShowSpeedMenu(!showSpeedMenu);
8843
8843
  }, [showSpeedMenu]);
8844
8844
  const toggleCaptions = useCallback3(() => {
8845
- if (!trackRef.current?.track || !subtitles) return;
8845
+ if (!trackRef.current?.track || !subtitles || subtitlesValidation !== "valid")
8846
+ return;
8846
8847
  const newShowCaptions = !showCaptions;
8847
8848
  setShowCaptions(newShowCaptions);
8848
- trackRef.current.track.mode = newShowCaptions && subtitles ? "showing" : "hidden";
8849
- }, [showCaptions, subtitles]);
8849
+ trackRef.current.track.mode = newShowCaptions ? "showing" : "hidden";
8850
+ }, [showCaptions, subtitles, subtitlesValidation]);
8850
8851
  const checkVideoCompletion = useCallback3(
8851
8852
  (progressPercent) => {
8852
8853
  if (progressPercent >= 95 && !hasCompleted) {
@@ -8874,11 +8875,58 @@ var VideoPlayer = ({
8874
8875
  setDuration(videoRef.current.duration);
8875
8876
  }
8876
8877
  }, []);
8878
+ useEffect15(() => {
8879
+ const controller = new AbortController();
8880
+ const validateSubtitles = async () => {
8881
+ if (!subtitles) {
8882
+ setSubtitlesValidation("idle");
8883
+ return;
8884
+ }
8885
+ setSubtitlesValidation("validating");
8886
+ try {
8887
+ if (subtitles.startsWith("data:")) {
8888
+ setSubtitlesValidation("valid");
8889
+ return;
8890
+ }
8891
+ const response = await fetch(subtitles, {
8892
+ method: "HEAD",
8893
+ signal: controller.signal
8894
+ });
8895
+ if (response.ok) {
8896
+ const contentType = response.headers.get("content-type");
8897
+ const isValidType = !contentType || contentType.includes("text/vtt") || contentType.includes("text/plain") || contentType.includes("application/octet-stream");
8898
+ if (isValidType) {
8899
+ setSubtitlesValidation("valid");
8900
+ } else {
8901
+ setSubtitlesValidation("invalid");
8902
+ console.warn(
8903
+ `Subtitles URL has invalid content type: ${contentType}`
8904
+ );
8905
+ }
8906
+ } else {
8907
+ setSubtitlesValidation("invalid");
8908
+ console.warn(
8909
+ `Subtitles URL returned status: ${response.status} ${response.statusText}`
8910
+ );
8911
+ }
8912
+ } catch (error) {
8913
+ if (error instanceof Error && error.name === "AbortError") {
8914
+ return;
8915
+ }
8916
+ console.warn("Subtitles URL validation failed:", error);
8917
+ setSubtitlesValidation("invalid");
8918
+ }
8919
+ };
8920
+ validateSubtitles();
8921
+ return () => {
8922
+ controller.abort();
8923
+ };
8924
+ }, [subtitles]);
8877
8925
  useEffect15(() => {
8878
8926
  if (trackRef.current?.track) {
8879
- trackRef.current.track.mode = showCaptions && subtitles ? "showing" : "hidden";
8927
+ trackRef.current.track.mode = showCaptions && subtitles && subtitlesValidation === "valid" ? "showing" : "hidden";
8880
8928
  }
8881
- }, [subtitles, showCaptions]);
8929
+ }, [subtitles, showCaptions, subtitlesValidation]);
8882
8930
  useEffect15(() => {
8883
8931
  const handleVisibilityChange = () => {
8884
8932
  if (document.hidden && isPlaying && videoRef.current) {
@@ -8932,61 +8980,57 @@ var VideoPlayer = ({
8932
8980
  const getBottomControlsOpacity = useCallback3(() => {
8933
8981
  return showControls ? "opacity-100" : "opacity-0";
8934
8982
  }, [showControls]);
8983
+ const seekBackward = useCallback3(() => {
8984
+ if (videoRef.current) {
8985
+ videoRef.current.currentTime -= 10;
8986
+ }
8987
+ }, []);
8988
+ const seekForward = useCallback3(() => {
8989
+ if (videoRef.current) {
8990
+ videoRef.current.currentTime += 10;
8991
+ }
8992
+ }, []);
8993
+ const increaseVolume = useCallback3(() => {
8994
+ handleVolumeChange(Math.min(100, volume * 100 + 10));
8995
+ }, [handleVolumeChange, volume]);
8996
+ const decreaseVolume = useCallback3(() => {
8997
+ handleVolumeChange(Math.max(0, volume * 100 - 10));
8998
+ }, [handleVolumeChange, volume]);
8935
8999
  const handleVideoKeyDown = useCallback3(
8936
9000
  (e) => {
8937
- if (e.key) {
8938
- e.stopPropagation();
8939
- showControlsWithTimer();
8940
- }
8941
- switch (e.key) {
8942
- case " ":
8943
- case "Enter":
8944
- e.preventDefault();
8945
- togglePlayPause();
8946
- break;
8947
- case "ArrowLeft":
8948
- e.preventDefault();
8949
- if (videoRef.current) {
8950
- videoRef.current.currentTime -= 10;
8951
- }
8952
- break;
8953
- case "ArrowRight":
8954
- e.preventDefault();
8955
- if (videoRef.current) {
8956
- videoRef.current.currentTime += 10;
8957
- }
8958
- break;
8959
- case "ArrowUp":
8960
- e.preventDefault();
8961
- handleVolumeChange(Math.min(100, volume * 100 + 10));
8962
- break;
8963
- case "ArrowDown":
8964
- e.preventDefault();
8965
- handleVolumeChange(Math.max(0, volume * 100 - 10));
8966
- break;
8967
- case "m":
8968
- case "M":
8969
- e.preventDefault();
8970
- toggleMute();
8971
- break;
8972
- case "f":
8973
- case "F":
8974
- e.preventDefault();
8975
- toggleFullscreen();
8976
- break;
8977
- default:
8978
- break;
9001
+ if (!e.key) return;
9002
+ e.stopPropagation();
9003
+ showControlsWithTimer();
9004
+ const keyHandlers = {
9005
+ " ": togglePlayPause,
9006
+ Enter: togglePlayPause,
9007
+ ArrowLeft: seekBackward,
9008
+ ArrowRight: seekForward,
9009
+ ArrowUp: increaseVolume,
9010
+ ArrowDown: decreaseVolume,
9011
+ m: toggleMute,
9012
+ M: toggleMute,
9013
+ f: toggleFullscreen,
9014
+ F: toggleFullscreen
9015
+ };
9016
+ const handler = keyHandlers[e.key];
9017
+ if (handler) {
9018
+ e.preventDefault();
9019
+ handler();
8979
9020
  }
8980
9021
  },
8981
9022
  [
8982
9023
  showControlsWithTimer,
8983
9024
  togglePlayPause,
8984
- handleVolumeChange,
8985
- volume,
9025
+ seekBackward,
9026
+ seekForward,
9027
+ increaseVolume,
9028
+ decreaseVolume,
8986
9029
  toggleMute,
8987
9030
  toggleFullscreen
8988
9031
  ]
8989
9032
  );
9033
+ const groupedSubTitleValid = subtitles && subtitlesValidation === "valid";
8990
9034
  return /* @__PURE__ */ jsxs31("div", { className: cn("flex flex-col", className), children: [
8991
9035
  (title || subtitleText) && /* @__PURE__ */ jsxs31("div", { className: "bg-subject-1 px-8 py-4 flex items-end justify-between min-h-20", children: [
8992
9036
  /* @__PURE__ */ jsxs31("div", { className: "flex flex-col gap-1", children: [
@@ -9060,9 +9104,9 @@ var VideoPlayer = ({
9060
9104
  {
9061
9105
  ref: trackRef,
9062
9106
  kind: "captions",
9063
- src: subtitles || "data:text/vtt;charset=utf-8,WEBVTT",
9107
+ src: groupedSubTitleValid ? subtitles : "data:text/vtt;charset=utf-8,WEBVTT",
9064
9108
  srcLang: "pt-br",
9065
- label: subtitles ? "Legendas em Portugu\xEAs" : "Sem legendas dispon\xEDveis",
9109
+ label: groupedSubTitleValid ? "Legendas em Portugu\xEAs" : "Sem legendas dispon\xEDveis",
9066
9110
  default: false
9067
9111
  }
9068
9112
  )
@@ -9151,7 +9195,7 @@ var VideoPlayer = ({
9151
9195
  showSlider: !isUltraSmallMobile
9152
9196
  }
9153
9197
  ),
9154
- subtitles && /* @__PURE__ */ jsx44(
9198
+ groupedSubTitleValid && /* @__PURE__ */ jsx44(
9155
9199
  IconButton_default,
9156
9200
  {
9157
9201
  icon: /* @__PURE__ */ jsx44(ClosedCaptioning, { size: getIconSize2() }),
@@ -10170,7 +10214,6 @@ var useQuizStore = create9()(
10170
10214
  const activityId = quiz.id;
10171
10215
  const userId = get().getUserId();
10172
10216
  if (!userId || userId === "") {
10173
- console.warn("selectAnswer called before userId is set");
10174
10217
  return;
10175
10218
  }
10176
10219
  const question = quiz.questions.find((q) => q.id === questionId);
@@ -10204,7 +10247,6 @@ var useQuizStore = create9()(
10204
10247
  const activityId = quiz.id;
10205
10248
  const userId = get().getUserId();
10206
10249
  if (!userId || userId === "") {
10207
- console.warn("selectMultipleAnswer called before userId is set");
10208
10250
  return;
10209
10251
  }
10210
10252
  const question = quiz.questions.find((q) => q.id === questionId);
@@ -10239,16 +10281,10 @@ var useQuizStore = create9()(
10239
10281
  const activityId = quiz.id;
10240
10282
  const userId = get().getUserId();
10241
10283
  if (!userId || userId === "") {
10242
- console.warn(
10243
- "selectDissertativeAnswer called before userId is set"
10244
- );
10245
10284
  return;
10246
10285
  }
10247
10286
  const question = quiz.questions.find((q) => q.id === questionId);
10248
10287
  if (!question || question.questionType !== "DISSERTATIVA" /* DISSERTATIVA */) {
10249
- console.warn(
10250
- "selectDissertativeAnswer called for non-dissertative question"
10251
- );
10252
10288
  return;
10253
10289
  }
10254
10290
  const existingAnswerIndex = userAnswers.findIndex(
@@ -10282,7 +10318,6 @@ var useQuizStore = create9()(
10282
10318
  const activityId = quiz.id;
10283
10319
  const userId = get().getUserId();
10284
10320
  if (!userId || userId === "") {
10285
- console.warn("skipQuestion called before userId is set");
10286
10321
  return;
10287
10322
  }
10288
10323
  const existingAnswerIndex = userAnswers.findIndex(
@@ -10315,7 +10350,6 @@ var useQuizStore = create9()(
10315
10350
  const activityId = quiz.id;
10316
10351
  const userId = get().getUserId();
10317
10352
  if (!userId || userId === "") {
10318
- console.warn("addUserAnswer called before userId is set");
10319
10353
  return;
10320
10354
  }
10321
10355
  const question = quiz.questions.find((q) => q.id === questionId);
@@ -10543,9 +10577,6 @@ var useQuizStore = create9()(
10543
10577
  );
10544
10578
  }
10545
10579
  if (questionIndex === -1) {
10546
- console.warn(
10547
- `Question with id "${question.id}" not found in active quiz`
10548
- );
10549
10580
  return;
10550
10581
  }
10551
10582
  set({ currentQuestionIndex: questionIndex });
@@ -11910,34 +11941,16 @@ var QuizFooter = forwardRef21(
11910
11941
  children: "Avan\xE7ar"
11911
11942
  }
11912
11943
  )
11913
- ] }) : /* @__PURE__ */ jsxs37("div", { className: "flex flex-row items-center justify-between w-full", children: [
11914
- /* @__PURE__ */ jsx51("span", { children: quiz?.canRetry && /* @__PURE__ */ jsx51(
11915
- Button_default,
11916
- {
11917
- variant: "link",
11918
- action: "primary",
11919
- size: "medium",
11920
- onClick: () => openModal("modalResolution"),
11921
- children: "Ver Resolu\xE7\xE3o"
11922
- }
11923
- ) }),
11924
- /* @__PURE__ */ jsx51(
11925
- Button_default,
11926
- {
11927
- variant: "solid",
11928
- action: "primary",
11929
- size: "medium",
11930
- onClick: () => {
11931
- if (quiz?.canRetry) {
11932
- onRepeat?.();
11933
- } else {
11934
- openModal("modalResolution");
11935
- }
11936
- },
11937
- children: quiz?.canRetry ? `Repetir ${getTypeLabel(quiz.type)}` : "Ver Resolu\xE7\xE3o"
11938
- }
11939
- )
11940
- ] })
11944
+ ] }) : /* @__PURE__ */ jsx51("div", { className: "flex flex-row items-center justify-center w-full", children: /* @__PURE__ */ jsx51(
11945
+ Button_default,
11946
+ {
11947
+ variant: "link",
11948
+ action: "primary",
11949
+ size: "medium",
11950
+ onClick: () => openModal("modalResolution"),
11951
+ children: "Ver resolu\xE7\xE3o"
11952
+ }
11953
+ ) })
11941
11954
  }
11942
11955
  ),
11943
11956
  /* @__PURE__ */ jsx51(
@@ -12216,17 +12229,32 @@ var QuizHeaderResult = forwardRef22(
12216
12229
  );
12217
12230
  }
12218
12231
  );
12219
- var QuizResultHeaderTitle = forwardRef22(({ className, showBadge = true, ...props }, ref) => {
12232
+ var QuizResultHeaderTitle = forwardRef22(({ className, showBadge = true, onRepeat, canRetry, ...props }, ref) => {
12220
12233
  const { quiz } = useQuizStore();
12221
12234
  return /* @__PURE__ */ jsxs38(
12222
12235
  "div",
12223
12236
  {
12224
12237
  ref,
12225
- className: cn("flex flex-row pt-4 justify-between", className),
12238
+ className: cn(
12239
+ "flex flex-row pt-4 justify-between items-center",
12240
+ className
12241
+ ),
12226
12242
  ...props,
12227
12243
  children: [
12228
12244
  /* @__PURE__ */ jsx52("p", { className: "text-text-950 font-bold text-2xl", children: "Resultado" }),
12229
- showBadge && /* @__PURE__ */ jsx52(QuizBadge, { subtype: quiz?.subtype || void 0 })
12245
+ /* @__PURE__ */ jsxs38("div", { className: "flex flex-row gap-3 items-center", children: [
12246
+ canRetry && onRepeat && /* @__PURE__ */ jsx52(
12247
+ Button_default,
12248
+ {
12249
+ variant: "solid",
12250
+ action: "primary",
12251
+ size: "medium",
12252
+ onClick: onRepeat,
12253
+ children: "Repetir question\xE1rio"
12254
+ }
12255
+ ),
12256
+ showBadge && /* @__PURE__ */ jsx52(QuizBadge, { subtype: quiz?.subtype || void 0 })
12257
+ ] })
12230
12258
  ]
12231
12259
  }
12232
12260
  );
@@ -12418,14 +12446,15 @@ var QuizListResult = forwardRef22(({ className, onSubjectClick, ...props }, ref)
12418
12446
  });
12419
12447
  var QuizListResultByMateria = ({
12420
12448
  subject,
12421
- onQuestionClick
12449
+ onQuestionClick,
12450
+ subjectName
12422
12451
  }) => {
12423
12452
  const { getQuestionsGroupedBySubject, getQuestionIndex } = useQuizStore();
12424
12453
  const groupedQuestions = getQuestionsGroupedBySubject();
12425
12454
  const answeredQuestions = groupedQuestions[subject] || [];
12426
12455
  const formattedQuestions = subject == "all" ? Object.values(groupedQuestions).flat() : answeredQuestions;
12427
12456
  return /* @__PURE__ */ jsxs38("div", { className: "flex flex-col", children: [
12428
- /* @__PURE__ */ jsx52("div", { className: "flex flex-row pt-4 justify-between", children: /* @__PURE__ */ jsx52("p", { className: "text-text-950 font-bold text-2xl", children: answeredQuestions?.[0]?.knowledgeMatrix?.[0]?.subject?.name ?? "Sem mat\xE9ria" }) }),
12457
+ /* @__PURE__ */ jsx52("div", { className: "flex flex-row pt-4 justify-between", children: /* @__PURE__ */ jsx52("p", { className: "text-text-950 font-bold text-2xl", children: subjectName || formattedQuestions?.[0]?.knowledgeMatrix?.[0]?.subject?.name || "Sem mat\xE9ria" }) }),
12429
12458
  /* @__PURE__ */ jsxs38("section", { className: "flex flex-col ", children: [
12430
12459
  /* @__PURE__ */ jsx52("p", { className: "pt-6 pb-4 text-text-950 font-bold text-lg", children: "Resultado das quest\xF5es" }),
12431
12460
  /* @__PURE__ */ jsx52("ul", { className: "flex flex-col gap-2 pt-4", children: formattedQuestions.map((question) => {