}));
+jest.mock("next/link", () => ({
+ __esModule: true,
+ default: ({ href, children }: any) =>
{children},
+}));
+jest.mock("@/helpers/image.helpers", () => ({
+ getScaledImageUri: (u: string) => `scaled:${u}`,
+ ImageScale: { W_AUTO_H_50: "x" },
+}));
+jest.mock(
+ "@/components/waves/winners/podium/WavePodiumItemContentOutcomes",
+ () => ({
+ WavePodiumItemContentOutcomes: () =>
,
+ })
+);
+jest.mock(
+ "@/components/waves/winners/podium/WaveWinnersPodiumPlaceholder",
+ () => ({
+ WaveWinnersPodiumPlaceholder: (props: any) => (
+
+ ),
+ })
+);
+jest.mock("@/components/waves/winners/identity/WaveWinnerIdentity", () => ({
+ WaveWinnerIdentity: () =>
,
+}));
const drop: any = {
- author: { handle: 'alice', pfp: 'pfp.png' },
+ author: { handle: "alice", pfp: "pfp.png" },
rating: 5,
raters_count: 1,
- wave: { voting_credit_type: 'CIC' },
+ wave: { voting_credit_type: "CIC" },
parts: [],
- metadata: []
+ metadata: [],
};
-it('renders placeholder when no winner', () => {
- render(
);
- expect(screen.getByTestId('placeholder')).toHaveAttribute('data-position','second');
+it("renders placeholder when no winner", () => {
+ render(
);
+ expect(screen.getByTestId("placeholder")).toHaveAttribute(
+ "data-position",
+ "second"
+ );
});
-it('calls onDropClick when clicked', () => {
+it("calls onDropClick when clicked", () => {
const onDropClick = jest.fn();
- render(
);
- fireEvent.click(screen.getByRole('link', { name: /alice/i }).parentElement!.parentElement!.parentElement!.parentElement!);
+ render(
+
+ );
+ expect(screen.getByTestId("identity")).toBeInTheDocument();
+ fireEvent.click(
+ screen.getByRole("link", { name: /alice/i }).parentElement!.parentElement!
+ .parentElement!.parentElement!
+ );
expect(onDropClick).toHaveBeenCalledWith(drop);
});
diff --git a/__tests__/helpers/waves/create-wave.helpers.extra.test.ts b/__tests__/helpers/waves/create-wave.helpers.extra.test.ts
index 6484cadf77..01af864ec0 100644
--- a/__tests__/helpers/waves/create-wave.helpers.extra.test.ts
+++ b/__tests__/helpers/waves/create-wave.helpers.extra.test.ts
@@ -1,67 +1,209 @@
-import { getCreateNewWaveBody } from '@/helpers/waves/create-wave.helpers';
-import { ApiWaveType } from '@/generated/models/ApiWaveType';
-import { ApiWaveMetadataType } from '@/generated/models/ApiWaveMetadataType';
+import { getCreateNewWaveBody } from "@/helpers/waves/create-wave.helpers";
+import { ApiWaveType } from "@/generated/models/ApiWaveType";
+import { ApiWaveMetadataType } from "@/generated/models/ApiWaveMetadataType";
-describe('create-wave.helpers extra', () => {
- it('clamps time weighted lock duration', () => {
+describe("create-wave.helpers extra", () => {
+ it("clamps time weighted lock duration", () => {
const config: any = {
- overview: { type: ApiWaveType.Rank, name: 'Wave' },
- groups: { canView:'1', canDrop:'2', canVote:'3', canChat:'4', admin:'5' },
- dates: { submissionStartDate:1, votingStartDate:2, endDate:null, firstDecisionTime:2, subsequentDecisions:[3], isRolling:false },
- drops: { noOfApplicationsAllowedPerParticipant:1, requiredTypes:[], requiredMetadata:[], terms:null, signatureRequired:false, adminCanDeleteDrops:false },
- chat: { enabled:true },
- voting: { type:null, category:null, profileId:null, timeWeighted:{ enabled:true, averagingInterval:1, averagingIntervalUnit:'minutes' } },
+ overview: { type: ApiWaveType.Rank, name: "Wave" },
+ groups: {
+ canView: "1",
+ canDrop: "2",
+ canVote: "3",
+ canChat: "4",
+ admin: "5",
+ },
+ dates: {
+ submissionStartDate: 1,
+ votingStartDate: 2,
+ endDate: null,
+ firstDecisionTime: 2,
+ subsequentDecisions: [3],
+ isRolling: false,
+ },
+ drops: {
+ noOfApplicationsAllowedPerParticipant: 1,
+ requiredTypes: [],
+ requiredMetadata: [],
+ submissionStrategy: null,
+ terms: null,
+ signatureRequired: false,
+ adminCanDeleteDrops: false,
+ },
+ chat: { enabled: true },
+ voting: {
+ type: null,
+ category: null,
+ profileId: null,
+ timeWeighted: {
+ enabled: true,
+ averagingInterval: 1,
+ averagingIntervalUnit: "minutes",
+ },
+ },
outcomes: [],
- approval: { threshold:null, thresholdTimeMs:null }
+ approval: { threshold: null, thresholdTimeMs: null },
};
- const drop: any = { parts:[], referenced_nfts:[], mentioned_users:[], metadata:[] };
- const body = getCreateNewWaveBody({ drop, picture:null, config });
+ const drop: any = {
+ parts: [],
+ referenced_nfts: [],
+ mentioned_users: [],
+ metadata: [],
+ };
+ const body = getCreateNewWaveBody({ drop, picture: null, config });
expect(body.wave.time_lock_ms).toBe(300000); // clamped to min 5 minutes
});
- it('throws when rolling without end date', () => {
+ it("throws when rolling without end date", () => {
const config: any = {
- overview: { type: ApiWaveType.Rank, name: 'W' },
- groups: { canView:'1', canDrop:'2', canVote:'3', canChat:'4', admin:'5' },
- dates: { submissionStartDate:1, votingStartDate:2, endDate:null, firstDecisionTime:2, subsequentDecisions:[3], isRolling:true },
- drops: { noOfApplicationsAllowedPerParticipant:1, requiredTypes:[], requiredMetadata:[{key:'k', type:ApiWaveMetadataType.String}], terms:null, signatureRequired:false, adminCanDeleteDrops:false },
- chat: { enabled:false },
- voting: { type:null, category:null, profileId:null, timeWeighted:{ enabled:false, averagingInterval:5, averagingIntervalUnit:'minutes' } },
+ overview: { type: ApiWaveType.Rank, name: "W" },
+ groups: {
+ canView: "1",
+ canDrop: "2",
+ canVote: "3",
+ canChat: "4",
+ admin: "5",
+ },
+ dates: {
+ submissionStartDate: 1,
+ votingStartDate: 2,
+ endDate: null,
+ firstDecisionTime: 2,
+ subsequentDecisions: [3],
+ isRolling: true,
+ },
+ drops: {
+ noOfApplicationsAllowedPerParticipant: 1,
+ requiredTypes: [],
+ requiredMetadata: [{ key: "k", type: ApiWaveMetadataType.String }],
+ submissionStrategy: null,
+ terms: null,
+ signatureRequired: false,
+ adminCanDeleteDrops: false,
+ },
+ chat: { enabled: false },
+ voting: {
+ type: null,
+ category: null,
+ profileId: null,
+ timeWeighted: {
+ enabled: false,
+ averagingInterval: 5,
+ averagingIntervalUnit: "minutes",
+ },
+ },
outcomes: [],
- approval: { threshold:null, thresholdTimeMs:null }
+ approval: { threshold: null, thresholdTimeMs: null },
};
- const drop: any = { parts:[], referenced_nfts:[], mentioned_users:[], metadata:[] };
- expect(() => getCreateNewWaveBody({ drop, picture:null, config })).toThrow('End date must be explicitly set when isRolling is true');
- });
-});
- it('calculates rolling end date correctly', () => {
- const config: any = {
- overview: { type: ApiWaveType.Rank, name: 'Wave' },
- groups: { canView:'1', canDrop:'2', canVote:'3', canChat:'4', admin:'5' },
- dates: { submissionStartDate:0, votingStartDate:0, endDate:65, firstDecisionTime:0, subsequentDecisions:[10,20], isRolling:true },
- drops: { noOfApplicationsAllowedPerParticipant:1, requiredTypes:[], requiredMetadata:[], terms:null, signatureRequired:false, adminCanDeleteDrops:false },
- chat: { enabled:false },
- voting: { type:null, category:null, profileId:null, timeWeighted:{ enabled:false, averagingInterval:5, averagingIntervalUnit:'minutes' } },
- outcomes: [],
- approval: { threshold:null, thresholdTimeMs:null }
+ const drop: any = {
+ parts: [],
+ referenced_nfts: [],
+ mentioned_users: [],
+ metadata: [],
};
- const drop:any = { parts:[], referenced_nfts:[], mentioned_users:[], metadata:[] };
- const body = getCreateNewWaveBody({ drop, picture:null, config });
- expect(body.voting.period.max).toBe(60); // last decision before 65
+ expect(() => getCreateNewWaveBody({ drop, picture: null, config })).toThrow(
+ "End date must be explicitly set when isRolling is true"
+ );
});
+});
+it("calculates rolling end date correctly", () => {
+ const config: any = {
+ overview: { type: ApiWaveType.Rank, name: "Wave" },
+ groups: {
+ canView: "1",
+ canDrop: "2",
+ canVote: "3",
+ canChat: "4",
+ admin: "5",
+ },
+ dates: {
+ submissionStartDate: 0,
+ votingStartDate: 0,
+ endDate: 65,
+ firstDecisionTime: 0,
+ subsequentDecisions: [10, 20],
+ isRolling: true,
+ },
+ drops: {
+ noOfApplicationsAllowedPerParticipant: 1,
+ requiredTypes: [],
+ requiredMetadata: [],
+ submissionStrategy: null,
+ terms: null,
+ signatureRequired: false,
+ adminCanDeleteDrops: false,
+ },
+ chat: { enabled: false },
+ voting: {
+ type: null,
+ category: null,
+ profileId: null,
+ timeWeighted: {
+ enabled: false,
+ averagingInterval: 5,
+ averagingIntervalUnit: "minutes",
+ },
+ },
+ outcomes: [],
+ approval: { threshold: null, thresholdTimeMs: null },
+ };
+ const drop: any = {
+ parts: [],
+ referenced_nfts: [],
+ mentioned_users: [],
+ metadata: [],
+ };
+ const body = getCreateNewWaveBody({ drop, picture: null, config });
+ expect(body.voting.period.max).toBe(60); // last decision before 65
+});
- it('sets winning thresholds for approve waves', () => {
- const config: any = {
- overview:{ type: ApiWaveType.Approve, name:'A' },
- groups:{ canView:'1', canDrop:'2', canVote:'3', canChat:'4', admin:'5' },
- dates:{ submissionStartDate:1, votingStartDate:2, endDate:null, firstDecisionTime:2, subsequentDecisions:[], isRolling:false },
- drops:{ noOfApplicationsAllowedPerParticipant:1, requiredTypes:[], requiredMetadata:[], terms:null, signatureRequired:false, adminCanDeleteDrops:false },
- chat:{ enabled:false },
- voting:{ type:null, category:null, profileId:null, timeWeighted:{ enabled:false, averagingInterval:5, averagingIntervalUnit:'minutes' } },
- outcomes: [],
- approval:{ threshold:3, thresholdTimeMs:null }
- };
- const drop:any = { parts:[], referenced_nfts:[], mentioned_users:[], metadata:[] };
- const body = getCreateNewWaveBody({ drop, picture:null, config });
- expect(body.wave.winning_thresholds).toEqual({ min:3, max:3 });
- });
+it("sets winning thresholds for approve waves", () => {
+ const config: any = {
+ overview: { type: ApiWaveType.Approve, name: "A" },
+ groups: {
+ canView: "1",
+ canDrop: "2",
+ canVote: "3",
+ canChat: "4",
+ admin: "5",
+ },
+ dates: {
+ submissionStartDate: 1,
+ votingStartDate: 2,
+ endDate: null,
+ firstDecisionTime: 2,
+ subsequentDecisions: [],
+ isRolling: false,
+ },
+ drops: {
+ noOfApplicationsAllowedPerParticipant: 1,
+ requiredTypes: [],
+ requiredMetadata: [],
+ submissionStrategy: null,
+ terms: null,
+ signatureRequired: false,
+ adminCanDeleteDrops: false,
+ },
+ chat: { enabled: false },
+ voting: {
+ type: null,
+ category: null,
+ profileId: null,
+ timeWeighted: {
+ enabled: false,
+ averagingInterval: 5,
+ averagingIntervalUnit: "minutes",
+ },
+ },
+ outcomes: [],
+ approval: { threshold: 3, thresholdTimeMs: null },
+ };
+ const drop: any = {
+ parts: [],
+ referenced_nfts: [],
+ mentioned_users: [],
+ metadata: [],
+ };
+ const body = getCreateNewWaveBody({ drop, picture: null, config });
+ expect(body.wave.winning_thresholds).toEqual({ min: 3, max: 3 });
+});
diff --git a/__tests__/helpers/waves/create-wave.helpers.test.ts b/__tests__/helpers/waves/create-wave.helpers.test.ts
index e1d242ddea..d422a5f73b 100644
--- a/__tests__/helpers/waves/create-wave.helpers.test.ts
+++ b/__tests__/helpers/waves/create-wave.helpers.test.ts
@@ -3,6 +3,9 @@ import {
getCreateWavePreviousStep,
calculateLastDecisionTime,
} from "@/helpers/waves/create-wave.helpers";
+import { ApiWaveParticipationIdentitySubmissionAllowDuplicates } from "@/generated/models/ApiWaveParticipationIdentitySubmissionAllowDuplicates";
+import { ApiWaveParticipationIdentitySubmissionWhoCanBeSubmitted } from "@/generated/models/ApiWaveParticipationIdentitySubmissionWhoCanBeSubmitted";
+import { ApiWaveParticipationSubmissionStrategyType } from "@/generated/models/ApiWaveParticipationSubmissionStrategyType";
import { ApiWaveType } from "@/generated/models/ApiWaveType";
import { ApiWaveMetadataType } from "@/generated/models/ApiWaveMetadataType";
import { CreateWaveStep } from "@/types/waves.types";
@@ -99,6 +102,7 @@ describe("create-wave.helpers", () => {
noOfApplicationsAllowedPerParticipant: 1,
requiredTypes: [],
requiredMetadata: [{ key: "m", type: ApiWaveMetadataType.String }],
+ submissionStrategy: null,
terms: null,
signatureRequired: false,
adminCanDeleteDrops: true,
@@ -132,5 +136,69 @@ describe("create-wave.helpers", () => {
expect(res.voting.period.max).toBe(2 + 3 + 5);
expect(res.wave.admin_drop_deletion_enabled).toBe(true);
});
+
+ it("includes identity submission strategy when configured", () => {
+ const {
+ getCreateNewWaveBody,
+ } = require("@/helpers/waves/create-wave.helpers");
+ const config = {
+ overview: { type: ApiWaveType.Rank, name: "W", image: null },
+ groups: {
+ canView: "1",
+ canDrop: "2",
+ canVote: "3",
+ canChat: "4",
+ admin: "5",
+ },
+ dates: {
+ submissionStartDate: 1,
+ votingStartDate: 2,
+ endDate: 10,
+ firstDecisionTime: 2,
+ subsequentDecisions: [],
+ isRolling: false,
+ },
+ drops: {
+ noOfApplicationsAllowedPerParticipant: 1,
+ requiredTypes: [],
+ requiredMetadata: [],
+ submissionStrategy: {
+ type: ApiWaveParticipationSubmissionStrategyType.Identity,
+ config: {
+ duplicates:
+ ApiWaveParticipationIdentitySubmissionAllowDuplicates.AllowAfterWin,
+ who_can_be_submitted:
+ ApiWaveParticipationIdentitySubmissionWhoCanBeSubmitted.OnlyOthers,
+ },
+ },
+ terms: null,
+ signatureRequired: false,
+ adminCanDeleteDrops: true,
+ },
+ chat: { enabled: true },
+ voting: {
+ type: null,
+ category: null,
+ profileId: null,
+ timeWeighted: {
+ enabled: false,
+ averagingInterval: 5,
+ averagingIntervalUnit: "minutes",
+ },
+ },
+ outcomes: [],
+ approval: { threshold: null, thresholdTimeMs: null },
+ } as any;
+ const drop = {
+ parts: [],
+ referenced_nfts: [],
+ mentioned_users: [],
+ metadata: [],
+ } as any;
+ const res = getCreateNewWaveBody({ drop, picture: "pic", config });
+ expect(res.participation.submission_strategy).toEqual(
+ config.drops.submissionStrategy
+ );
+ });
});
});
diff --git a/__tests__/helpers/waves/create-wave.validation.test.ts b/__tests__/helpers/waves/create-wave.validation.test.ts
index ebe89b0f5c..57dba6e3cb 100644
--- a/__tests__/helpers/waves/create-wave.validation.test.ts
+++ b/__tests__/helpers/waves/create-wave.validation.test.ts
@@ -28,6 +28,7 @@ describe("create-wave.validation", () => {
noOfApplicationsAllowedPerParticipant: null,
requiredTypes: [],
requiredMetadata: [],
+ submissionStrategy: null,
terms: null,
signatureRequired: false,
adminCanDeleteDrops: false,
@@ -128,6 +129,72 @@ describe("create-wave.validation", () => {
);
});
+ it("rejects reserved identity metadata keys for identity nomination waves", () => {
+ const config = {
+ ...baseConfig,
+ drops: {
+ ...baseConfig.drops,
+ requiredMetadata: [{ key: " Identity ", type: "t" }],
+ submissionStrategy: {
+ type: "IDENTITY",
+ config: {
+ duplicates: "NEVER_ALLOW",
+ who_can_be_submitted: "EVERYONE",
+ },
+ },
+ },
+ };
+ const errors = getCreateWaveValidationErrors({
+ step: CreateWaveStep.DROPS,
+ config,
+ });
+ expect(errors).toContain(
+ CREATE_WAVE_VALIDATION_ERROR.DROPS_REQUIRED_METADATA_RESERVED_IDENTITY_KEY
+ );
+ });
+
+ it("allows identity metadata keys for standard drop waves", () => {
+ const config = {
+ ...baseConfig,
+ drops: {
+ ...baseConfig.drops,
+ requiredMetadata: [{ key: "IDENTITY", type: "t" }],
+ submissionStrategy: null,
+ },
+ };
+ const errors = getCreateWaveValidationErrors({
+ step: CreateWaveStep.DROPS,
+ config,
+ });
+ expect(errors).not.toContain(
+ CREATE_WAVE_VALIDATION_ERROR.DROPS_REQUIRED_METADATA_RESERVED_IDENTITY_KEY
+ );
+ });
+
+ it("chat waves cannot have submission strategy", () => {
+ const config = {
+ ...baseConfig,
+ overview: { type: ApiWaveType.Chat, name: "n", image: null },
+ drops: {
+ ...baseConfig.drops,
+ submissionStrategy: {
+ type: "IDENTITY",
+ config: {
+ duplicates: "NEVER_ALLOW",
+ who_can_be_submitted: "EVERYONE",
+ },
+ },
+ },
+ };
+ const errors = getCreateWaveValidationErrors({
+ step: CreateWaveStep.DROPS,
+ config,
+ });
+ expect(errors).toContain(
+ CREATE_WAVE_VALIDATION_ERROR.DROPS_SUBMISSION_STRATEGY_INVALID
+ );
+ });
+
it("approval threshold time must be smaller than duration", () => {
const config = {
...baseConfig,
diff --git a/__tests__/helpers/waves/wave-submission-experience.helpers.test.ts b/__tests__/helpers/waves/wave-submission-experience.helpers.test.ts
new file mode 100644
index 0000000000..aa8a6365ae
--- /dev/null
+++ b/__tests__/helpers/waves/wave-submission-experience.helpers.test.ts
@@ -0,0 +1,64 @@
+import {
+ resolveWaveSubmissionExperience,
+ WaveSubmissionExperience,
+} from "@/helpers/waves/wave-submission-experience.helpers";
+
+describe("resolveWaveSubmissionExperience", () => {
+ it("prefers memes legacy behavior over submission strategy", () => {
+ expect(
+ resolveWaveSubmissionExperience({
+ isMemesWave: true,
+ isCurationWave: false,
+ submissionStrategy: {
+ type: "IDENTITY" as any,
+ config: {
+ who_can_be_submitted: "EVERYONE" as any,
+ duplicates: "NEVER_ALLOW" as any,
+ },
+ },
+ })
+ ).toBe(WaveSubmissionExperience.MEMES_LEGACY);
+ });
+
+ it("prefers curation legacy behavior over submission strategy", () => {
+ expect(
+ resolveWaveSubmissionExperience({
+ isMemesWave: false,
+ isCurationWave: true,
+ submissionStrategy: {
+ type: "IDENTITY" as any,
+ config: {
+ who_can_be_submitted: "EVERYONE" as any,
+ duplicates: "NEVER_ALLOW" as any,
+ },
+ },
+ })
+ ).toBe(WaveSubmissionExperience.CURATION_LEGACY);
+ });
+
+ it("uses identity experience for non-legacy waves with submission strategy", () => {
+ expect(
+ resolveWaveSubmissionExperience({
+ isMemesWave: false,
+ isCurationWave: false,
+ submissionStrategy: {
+ type: "IDENTITY" as any,
+ config: {
+ who_can_be_submitted: "EVERYONE" as any,
+ duplicates: "NEVER_ALLOW" as any,
+ },
+ },
+ })
+ ).toBe(WaveSubmissionExperience.IDENTITY);
+ });
+
+ it("falls back to default when no special behavior applies", () => {
+ expect(
+ resolveWaveSubmissionExperience({
+ isMemesWave: false,
+ isCurationWave: false,
+ submissionStrategy: null,
+ })
+ ).toBe(WaveSubmissionExperience.DEFAULT);
+ });
+});
diff --git a/__tests__/hooks/waves/useWaveDecisions.test.ts b/__tests__/hooks/waves/useWaveDecisions.test.ts
index e64210bede..a047c04ba8 100644
--- a/__tests__/hooks/waves/useWaveDecisions.test.ts
+++ b/__tests__/hooks/waves/useWaveDecisions.test.ts
@@ -11,6 +11,10 @@ jest.mock("@/services/api/common-api");
const useQueryMock = useQuery as jest.Mock;
const fetchMock = commonApiFetch as jest.Mock;
+const makeWinner = (place: number, id = `drop-${place}`) => ({
+ place,
+ drop: { id },
+});
describe("useWaveDecisions", () => {
beforeEach(() => {
@@ -27,15 +31,15 @@ describe("useWaveDecisions", () => {
it("configures a single-page query and sorts loaded decisions", () => {
const unsortedDecision = {
decision_time: 2,
- winners: [{ place: 2 }, { place: 1 }],
+ winners: [makeWinner(2), makeWinner(1)],
};
useQueryMock.mockReturnValue({
data: {
data: [
- { decision_time: 3, winners: [{ place: 3 }, { place: 1 }] },
+ { decision_time: 3, winners: [makeWinner(3), makeWinner(1)] },
unsortedDecision,
- { decision_time: 1, winners: [{ place: 1 }] },
+ { decision_time: 1, winners: [makeWinner(1)] },
],
},
isError: false,
@@ -60,6 +64,36 @@ describe("useWaveDecisions", () => {
).toEqual([1, 2]);
});
+ it("warns when winners are missing drop data and keeps sorted winners", () => {
+ const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
+
+ useQueryMock.mockReturnValue({
+ data: {
+ data: [
+ {
+ decision_time: 2,
+ winners: [makeWinner(2), { place: 1 }],
+ },
+ ],
+ },
+ isError: false,
+ error: null,
+ refetch: jest.fn(),
+ isFetching: false,
+ });
+
+ const { result } = renderHook(() => useWaveDecisions({ waveId: "w1" }));
+
+ expect(
+ result.current.decisionPoints[0]?.winners.map((winner) => winner.place)
+ ).toEqual([1, 2]);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining("Found 1 winner(s) without drop data")
+ );
+
+ warnSpy.mockRestore();
+ });
+
it("requests the first page of decisions", async () => {
fetchMock.mockResolvedValue({
data: [],
diff --git a/components/brain/my-stream/MyStreamWaveChat.tsx b/components/brain/my-stream/MyStreamWaveChat.tsx
index c2c6058fee..2a41b0510e 100644
--- a/components/brain/my-stream/MyStreamWaveChat.tsx
+++ b/components/brain/my-stream/MyStreamWaveChat.tsx
@@ -17,6 +17,10 @@ import type { ApiDrop } from "@/generated/models/ApiDrop";
import type { ApiWave } from "@/generated/models/ApiWave";
import { getHomeRoute } from "@/helpers/navigation.helpers";
import type { ExtendedDrop } from "@/helpers/waves/drop.helpers";
+import {
+ resolveWaveSubmissionExperience,
+ WaveSubmissionExperience,
+} from "@/helpers/waves/wave-submission-experience.helpers";
import useDeviceInfo from "@/hooks/useDeviceInfo";
import { useWave } from "@/hooks/useWave";
import type { WaveViewMode } from "@/hooks/useWaveViewMode";
@@ -96,7 +100,12 @@ const MyStreamWaveChat: React.FC
= ({
const searchParams = useSearchParams();
const pathname = usePathname();
const containerRef = useRef(null);
- const { isMemesWave } = useWave(wave);
+ const { isMemesWave, isCurationWave } = useWave(wave);
+ const submissionExperience = resolveWaveSubmissionExperience({
+ isMemesWave,
+ isCurationWave,
+ submissionStrategy: wave.participation.submission_strategy ?? null,
+ });
const editingDropId = useSelector(selectEditingDropId);
const { isApp } = useDeviceInfo();
@@ -264,7 +273,9 @@ const MyStreamWaveChat: React.FC = ({
)}
- {isMemesWave &&