Skip to content

Commit 2485ded

Browse files
iHiDclaudedem4ron
authored
Fix invalid hook call in handleSyncEverything (#8460)
* Fix invalid hook call in handleSyncEverything The handleSyncEverything function was a standalone exported function that called useAppTranslation (a React hook), violating the Rules of Hooks. It was called from onClick handlers, outside the component render cycle. Move the logic into useCallback hooks inside the respective components, matching the pattern already used by handleSyncSingleTrack. Closes #8452 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * DRY --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dem4ron <demaaron88@gmail.com>
1 parent b2eea99 commit 2485ded

3 files changed

Lines changed: 45 additions & 42 deletions

File tree

app/javascript/components/settings/github-syncer/sections/ConnectedSection/JustConnectedModal.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import React from 'react'
22
import Modal from '@/components/modals/Modal'
33
import { GitHubSyncerContext } from '../../GitHubSyncerForm'
44
import { Icon } from '@/components/common'
5-
import { handleSyncEverything } from './ManualSyncSection'
65
import { useAppTranslation } from '@/i18n/useAppTranslation'
6+
import { useSyncEverything } from '../../useSyncEverything'
77

88
export function JustConnectedModal(): JSX.Element {
99
const { t } = useAppTranslation(
1010
'components/settings/github-syncer/sections/ConnectedSection'
1111
)
1212
const { links } = React.useContext(GitHubSyncerContext)
1313
const [isModalOpen, setIsModalOpen] = React.useState(false)
14+
const syncEverything = useSyncEverything(links.syncEverything)
1415

1516
React.useEffect(() => {
1617
const searchParams = new URLSearchParams(window.location.search)
@@ -27,9 +28,9 @@ export function JustConnectedModal(): JSX.Element {
2728
}, [])
2829

2930
const handleSync = React.useCallback(() => {
30-
handleSyncEverything({ syncEverythingEndpoint: links.syncEverything })
31+
syncEverything()
3132
handleRemoveParam()
32-
}, [links.syncEverything])
33+
}, [syncEverything, handleRemoveParam])
3334

3435
const handleCloseModal = React.useCallback(() => {
3536
handleRemoveParam()

app/javascript/components/settings/github-syncer/sections/ConnectedSection/ManualSyncSection.tsx

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { fetchWithParams, handleJsonErrorResponse } from '../../fetchWithParams'
66
import { StaticTooltip } from '@/components/bootcamp/JikiscriptExercisePage/Scrubber/ScrubberTooltipInformation'
77
import { useAppTranslation } from '@/i18n/useAppTranslation'
88
import { Trans } from 'react-i18next'
9+
import { useSyncEverything } from '../../useSyncEverything'
910

1011
type Track = {
1112
title: string
@@ -52,6 +53,8 @@ export function ManualSyncSection() {
5253
[links.syncTrack, t]
5354
)
5455

56+
const handleSyncEverything = useSyncEverything(links.syncEverything)
57+
5558
return (
5659
<section
5760
style={{
@@ -119,11 +122,7 @@ export function ManualSyncSection() {
119122
<div className="group relative">
120123
<button
121124
disabled={!isSyncingEnabled}
122-
onClick={() =>
123-
handleSyncEverything({
124-
syncEverythingEndpoint: links.syncEverything,
125-
})
126-
}
125+
onClick={handleSyncEverything}
127126
className="btn btn-primary relative group"
128127
>
129128
{t('backupEverythingLabel')}
@@ -139,37 +138,3 @@ export function ManualSyncSection() {
139138
</section>
140139
)
141140
}
142-
143-
export function handleSyncEverything({
144-
syncEverythingEndpoint,
145-
}: {
146-
syncEverythingEndpoint: string
147-
}) {
148-
const { t } = useAppTranslation(
149-
'components/settings/github-syncer/sections/ConnectedSection/ManualSyncSection.tsx'
150-
)
151-
fetchWithParams({
152-
url: syncEverythingEndpoint,
153-
})
154-
.then(async (response) => {
155-
if (response.ok) {
156-
toast.success(
157-
t(
158-
'yourBackupForAllTracksHasBeenQueuedAndShouldBeCompletedWithinAFewMinutes'
159-
),
160-
{ duration: 5000 }
161-
)
162-
} else {
163-
await handleJsonErrorResponse(
164-
response,
165-
t('errorQueuingBackupForAllTracks')
166-
)
167-
}
168-
})
169-
.catch((error) => {
170-
console.error('Error:', error)
171-
toast.error(
172-
t('somethingWentWrongWhileQueuingTheBackupForAllTracksPleaseTryAgain')
173-
)
174-
})
175-
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useCallback } from 'react'
2+
import toast from 'react-hot-toast'
3+
import { fetchWithParams, handleJsonErrorResponse } from './fetchWithParams'
4+
import { useAppTranslation } from '@/i18n/useAppTranslation'
5+
6+
export function useSyncEverything(syncEverythingEndpoint: string) {
7+
const { t } = useAppTranslation(
8+
'components/settings/github-syncer/sections/ConnectedSection/ManualSyncSection.tsx'
9+
)
10+
11+
return useCallback(() => {
12+
fetchWithParams({
13+
url: syncEverythingEndpoint,
14+
})
15+
.then(async (response) => {
16+
if (response.ok) {
17+
toast.success(
18+
t(
19+
'yourBackupForAllTracksHasBeenQueuedAndShouldBeCompletedWithinAFewMinutes'
20+
),
21+
{ duration: 5000 }
22+
)
23+
} else {
24+
await handleJsonErrorResponse(
25+
response,
26+
t('errorQueuingBackupForAllTracks')
27+
)
28+
}
29+
})
30+
.catch((error) => {
31+
console.error('Error:', error)
32+
toast.error(
33+
t('somethingWentWrongWhileQueuingTheBackupForAllTracksPleaseTryAgain')
34+
)
35+
})
36+
}, [syncEverythingEndpoint, t])
37+
}

0 commit comments

Comments
 (0)