diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx index bb754c6c..2ffa71aa 100644 --- a/src/components/post-form/post-form.tsx +++ b/src/components/post-form/post-form.tsx @@ -24,7 +24,7 @@ import { getPublishURLFilename, isValidPublishURL, isValidURL } from '../../lib/ import { hasModQueueAccessRole } from '../../lib/utils/mod-access'; import { getBoardPath } from '../../lib/utils/route-utils'; import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils'; -import { getCommentFlagOptionsForDirectory, getCommentFlagPublishOptionsFromSelection, type CommentFlagSelectOption } from '../../lib/comment-flag-selection'; +import { getCommentFlagOptionsForDirectory, getCommentFlagPublishOptionsForDirectory, type CommentFlagSelectOption } from '../../lib/comment-flag-selection'; import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses'; import { useDirectories, useDirectoryByAddress } from '../../hooks/use-directories'; import { useCommunityField } from '../../hooks/use-stable-community'; @@ -576,7 +576,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid: return; } - const flagPublishOptions = getCommentFlagPublishOptionsFromSelection(flagRef.current?.value); + const flagPublishOptions = getCommentFlagPublishOptionsForDirectory(directoryEntry, flagRef.current?.value); nonokoRedirectPathRef.current = hasNonokoOption(currentOptions) ? getBoardIndexPath() : null; publishPost({ content: publishContent, ...flagPublishOptions }); @@ -688,7 +688,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid: return; } - const flagPublishOptions = getCommentFlagPublishOptionsFromSelection(flagRef.current?.value); + const flagPublishOptions = getCommentFlagPublishOptionsForDirectory(directoryEntry, flagRef.current?.value); nonokoRedirectPathRef.current = hasNonokoOption(currentOptions) ? getBoardIndexPath() : null; publishReply({ content: publishContent, ...flagPublishOptions }); diff --git a/src/components/reply-modal/__tests__/reply-modal.test.tsx b/src/components/reply-modal/__tests__/reply-modal.test.tsx index 1210de8a..cf4a2e0e 100644 --- a/src/components/reply-modal/__tests__/reply-modal.test.tsx +++ b/src/components/reply-modal/__tests__/reply-modal.test.tsx @@ -329,6 +329,12 @@ describe('ReplyModal', () => { features: { hasFlags: true }, title: '/pol/ - Politically Incorrect', }, + 'international-nsfw.bso': { + address: 'international-nsfw.bso', + directoryCode: 'bant', + features: { hasFlags: true }, + title: '/bant/ - International/Random', + }, 'random-nsfw.bso': { address: 'random-nsfw.bso', features: {}, @@ -443,6 +449,24 @@ describe('ReplyModal', () => { .slice(0, 3) .map((option) => option.textContent), ).toEqual(['Geographic Location', 'Anarcho-Capitalist', 'Anarchist']); + const linkInput = container.querySelectorAll('input[type="text"]')[2]; + expect(Boolean(linkInput!.compareDocumentPosition(flagSelect!) & Node.DOCUMENT_POSITION_FOLLOWING)).toBe(true); + + await clickButtonByText('post'); + + expect(testState.publishReplyMock).toHaveBeenCalledWith({ + content: '>>42\nselected text', + challengeRequest: { + challengeAnswers: ['bitsocial-flags:5chan:flag:country:auto'], + }, + flairs: [{ type: 'country', code: 'auto', text: 'flag:country:auto' }], + }); + }); + + it('publishes geographic location on /bant/ without showing a flag selector', async () => { + await renderReplyModal('/bant/thread/post-1', 'international-nsfw.bso'); + + expect(container.querySelector('select[aria-label="flag"]')).toBeNull(); await clickButtonByText('post'); diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx index 2d33cf35..a5611b6d 100644 --- a/src/components/reply-modal/reply-modal.tsx +++ b/src/components/reply-modal/reply-modal.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { setAccount, useAccount } from '@bitsocial/bitsocial-react-hooks'; import { getExpiringMediaLinkAlert } from '../../lib/utils/media-link-validation-utils'; -import { getCommentFlagOptionsForDirectory, getCommentFlagPublishOptionsFromSelection } from '../../lib/comment-flag-selection'; +import { getCommentFlagOptionsForDirectory, getCommentFlagPublishOptionsForDirectory } from '../../lib/comment-flag-selection'; import { type DiceRoll, type FortuneEntry, @@ -169,7 +169,7 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, parentNumber, threa return; } - const flagPublishOptions = getCommentFlagPublishOptionsFromSelection(flagRef.current?.value); + const flagPublishOptions = getCommentFlagPublishOptionsForDirectory(directoryEntry, flagRef.current?.value); setError(null); nonokoRedirectPathRef.current = hasNonokoOption(currentOptions) ? `/${postOptionsDirectoryCode || params.boardIdentifier || communityAddress}` : null; @@ -520,6 +520,19 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, parentNumber, threa }} /> +
+ { + setUrl(e.target.value); + setPublishReplyOptions({ link: e.target.value }); + }} + /> +
{flagOptions.length > 0 && (
{ - setUrl(e.target.value); - setPublishReplyOptions({ link: e.target.value }); - }} - /> -
{showUploadControls && ( diff --git a/src/lib/__tests__/comment-flag-selection.test.ts b/src/lib/__tests__/comment-flag-selection.test.ts index fd58c4ed..6037a23c 100644 --- a/src/lib/__tests__/comment-flag-selection.test.ts +++ b/src/lib/__tests__/comment-flag-selection.test.ts @@ -1,5 +1,10 @@ import { describe, expect, it } from 'vitest'; -import { getCommentFlagOptionsForDirectory, getCommentFlagPublishOptionsFromSelection, getCommentFlagRequestFromSelection } from '../comment-flag-selection'; +import { + getCommentFlagOptionsForDirectory, + getCommentFlagPublishOptionsForDirectory, + getCommentFlagPublishOptionsFromSelection, + getCommentFlagRequestFromSelection, +} from '../comment-flag-selection'; describe('comment-flag-selection', () => { it('does not expose options for boards without flags', () => { @@ -16,6 +21,29 @@ describe('comment-flag-selection', () => { ).toEqual([{ label: 'Geographic Location', value: 'country:auto' }]); }); + it('does not expose a flag selector on /bant/ but still publishes geographic location', () => { + expect( + getCommentFlagOptionsForDirectory({ + directoryCode: 'bant', + features: { hasFlags: true }, + title: '/bant/ - International/Random', + }), + ).toEqual([]); + + expect( + getCommentFlagPublishOptionsForDirectory({ + directoryCode: 'bant', + features: { hasFlags: true }, + title: '/bant/ - International/Random', + }), + ).toEqual({ + challengeRequest: { + challengeAnswers: ['bitsocial-flags:5chan:flag:country:auto'], + }, + flairs: [{ type: 'country', code: 'auto', text: 'flag:country:auto' }], + }); + }); + it('matches the 4chan /pol/ flag order', () => { const options = getCommentFlagOptionsForDirectory({ directoryCode: 'pol', diff --git a/src/lib/comment-flag-selection.ts b/src/lib/comment-flag-selection.ts index e0891395..18c6d822 100644 --- a/src/lib/comment-flag-selection.ts +++ b/src/lib/comment-flag-selection.ts @@ -35,6 +35,9 @@ const NO_FLAG_OPTION: CommentFlagSelectOption = { label: 'None', }; +/** Boards that always publish geographic location without showing a flag selector. */ +const AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES = new Set(['bant']); + const getDirectoryCode = (directory: Pick | undefined): string | undefined => { const directoryCode = directory?.directoryCode?.trim().toLowerCase(); return directoryCode || directory?.title?.match(/^\/([^/]+)\//)?.[1]?.toLowerCase(); @@ -52,6 +55,10 @@ export const getCommentFlagOptionsForDirectory = (directory: Pick | undefined, + selectedValue?: string, +): CommentFlagPublishOptions => { + if (directory?.features?.hasFlags !== true) { + return { + challengeRequest: undefined, + flairs: undefined, + }; + } + + const directoryCode = getDirectoryCode(directory); + if (directoryCode && AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES.has(directoryCode)) { + return getCommentFlagPublishOptionsFromSelection(GEOGRAPHIC_LOCATION_FLAG_VALUE); + } + + const flagOptions = getCommentFlagOptionsForDirectory(directory); + if (flagOptions.length === 0) { + return { + challengeRequest: undefined, + flairs: undefined, + }; + } + + return getCommentFlagPublishOptionsFromSelection(selectedValue ?? flagOptions[0]?.value); +}; + export const getCommentFlagRequestFromSelection = (value: string | undefined): CommentFlagRequest | undefined => { if (!value || value === NO_FLAG_VALUE) { return undefined;