linguabot commited on
Commit
ffd3124
·
verified ·
1 Parent(s): 9f662c1

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. client/src/pages/TutorialTasks.tsx +37 -7
client/src/pages/TutorialTasks.tsx CHANGED
@@ -857,11 +857,24 @@ const TutorialTasks: React.FC = () => {
857
  return { ...prev, [taskId]: next };
858
  });
859
 
860
- // Defer only local state clears; skip refetch to avoid DOM churn
 
 
 
 
861
  withPreservedCardOffset(taskId, () => {
862
  React.startTransition(() => {
863
  setTranslationText({ ...translationText, [taskId]: '' });
864
  setSelectedGroups({ ...selectedGroups, [taskId]: 0 });
 
 
 
 
 
 
 
 
 
865
  });
866
  });
867
  } else {
@@ -874,12 +887,12 @@ const TutorialTasks: React.FC = () => {
874
  withPreservedCardOffset(taskId, () => {
875
  setSubmitting({ ...submitting, [taskId]: false });
876
  });
877
- // release after a couple frames to let DOM settle
878
- requestAnimationFrame(() => requestAnimationFrame(() => {
879
  unlockListHeight();
880
  unlockCardHeightById(taskId);
881
  unlockGridHeightById(taskId);
882
- }));
883
  setMutatingTaskId(null);
884
  }
885
  };
@@ -941,10 +954,27 @@ const TutorialTasks: React.FC = () => {
941
  });
942
  }
943
 
944
- // Skip refetch entirely to avoid layout churn; UI already updated optimistically
945
  if (taskId) lockCardHeightById(taskId);
946
  withPreservedCardOffset(taskId || '', () => {
947
- React.startTransition(() => {});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
948
  });
949
  } else {
950
 
@@ -2253,7 +2283,7 @@ const TutorialTasks: React.FC = () => {
2253
  expandedSections[task._id]
2254
  ? 'max-h-none overflow-visible'
2255
  : 'max-h-0 overflow-hidden'
2256
- }`}>
2257
  {userSubmissions[task._id].map((submission, index) => (
2258
  <div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
2259
  <div className="flex items-center justify-between mb-2">
 
857
  return { ...prev, [taskId]: next };
858
  });
859
 
860
+ // Defer state updates and minimal refetch
861
+ // Measure grid height and set spacer before refetch to keep layout height constant
862
+ const gridEl = submissionsGridRefs.current[taskId];
863
+ const gridHeight = gridEl ? gridEl.getBoundingClientRect().height : 0;
864
+ if (gridHeight > 0) setSpacerHeights(prev => ({ ...prev, [taskId]: gridHeight }));
865
  withPreservedCardOffset(taskId, () => {
866
  React.startTransition(() => {
867
  setTranslationText({ ...translationText, [taskId]: '' });
868
  setSelectedGroups({ ...selectedGroups, [taskId]: 0 });
869
+ // Narrow refetch: only this task's submissions
870
+ api.get(`/api/submissions/by-source/${taskId}`).then(r => {
871
+ const list = (r.data && r.data.submissions) || [];
872
+ setUserSubmissions(prev => ({ ...prev, [taskId]: list }));
873
+ // Release spacer one frame after list update to avoid jump
874
+ requestAnimationFrame(() => setSpacerHeights(prev => ({ ...prev, [taskId]: 0 })));
875
+ }).catch(() => {
876
+ requestAnimationFrame(() => setSpacerHeights(prev => ({ ...prev, [taskId]: 0 })));
877
+ });
878
  });
879
  });
880
  } else {
 
887
  withPreservedCardOffset(taskId, () => {
888
  setSubmitting({ ...submitting, [taskId]: false });
889
  });
890
+ // release after a few frames to let Safari settle layout
891
+ requestAnimationFrame(() => requestAnimationFrame(() => requestAnimationFrame(() => {
892
  unlockListHeight();
893
  unlockCardHeightById(taskId);
894
  unlockGridHeightById(taskId);
895
+ })));
896
  setMutatingTaskId(null);
897
  }
898
  };
 
954
  });
955
  }
956
 
957
+ // Defer refetch to prevent UI jumping and preserve scroll around DOM updates
958
  if (taskId) lockCardHeightById(taskId);
959
  withPreservedCardOffset(taskId || '', () => {
960
+ React.startTransition(() => {
961
+ // Narrow refetch: only this task's submissions
962
+ if (taskId) {
963
+ const gridEl = submissionsGridRefs.current[taskId];
964
+ const gridHeight = gridEl ? gridEl.getBoundingClientRect().height : 0;
965
+ if (gridHeight > 0) setSpacerHeights(prev => ({ ...prev, [taskId]: gridHeight }));
966
+ api.get(`/api/submissions/by-source/${taskId}`).then(r => {
967
+ const list = (r.data && r.data.submissions) || [];
968
+ setUserSubmissions(prev => ({ ...prev, [taskId]: list }));
969
+ requestAnimationFrame(() => setSpacerHeights(prev => ({ ...prev, [taskId]: 0 })));
970
+ }).catch(() => {
971
+ requestAnimationFrame(() => setSpacerHeights(prev => ({ ...prev, [taskId]: 0 })));
972
+ });
973
+ } else {
974
+ // Fallback
975
+ requestAnimationFrame(() => requestAnimationFrame(() => fetchUserSubmissions(tutorialTasks)));
976
+ }
977
+ });
978
  });
979
  } else {
980
 
 
2283
  expandedSections[task._id]
2284
  ? 'max-h-none overflow-visible'
2285
  : 'max-h-0 overflow-hidden'
2286
+ }`} style={{ contain: 'layout paint size' }}>
2287
  {userSubmissions[task._id].map((submission, index) => (
2288
  <div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
2289
  <div className="flex items-center justify-between mb-2">