Using the bonus mixins on repeatables and challenges

As of Profectus 0.7, decorators got replaced with mixins and wrappers. Since mixins require creating or extending a feature, and the bonus decorators became a mixin, I wanted to share exactly how to extend the repeatable and challenge to use bonus amounts/completions. These will work out of the box and are well type annotated.

bonusRepeatable.ts:

import { createRepeatable, Repeatable, RepeatableOptions } from "features/clickables/repeatable";
import { bonusAmountMixin } from "mixins/bonusAmount";
import { DecimalSource } from "util/bignum";
import { createLazyProxy } from "util/proxies";
import { MaybeRef, MaybeRefOrGetter, Ref } from "vue";

export interface BonusRepeatableOptions extends RepeatableOptions {
    bonusAmount: MaybeRefOrGetter<DecimalSource>;
}

export interface BonusRepeatable extends Repeatable {
    bonusAmount: MaybeRef<DecimalSource>;
    totalAmount: Ref<DecimalSource>;
}

export function createBonusRepeatable(optionsFunc: () => BonusRepeatableOptions) {
    return createLazyProxy(() => {
        const repeatable = createRepeatable(optionsFunc);

        const bonusRepeatable = {
            ...repeatable,
            ...bonusAmountMixin(repeatable.amount, repeatable.bonusAmount)
        } satisfies BonusRepeatable;

        return bonusRepeatable;
    });
}

bonusChallenge.ts:

import { Challenge, ChallengeOptions, createChallenge } from "features/challenges/challenge";
import { bonusAmountMixin } from "mixins/bonusAmount";
import { DecimalSource } from "util/bignum";
import { createLazyProxy } from "util/proxies";
import { MaybeRef, MaybeRefOrGetter, Ref } from "vue";

export interface BonusChallengeOptions extends ChallengeOptions {
    bonusCompletions: MaybeRefOrGetter<DecimalSource>;
}

export interface BonusChallenge extends Challenge {
    bonusCompletions: MaybeRef<DecimalSource>;
    totalCompletions: Ref<DecimalSource>;
}

export function createBonusChallenge(optionsFunc: () => BonusChallengeOptions) {
    return createLazyProxy(() => {
        const challenge = createChallenge(optionsFunc);

        const { bonusAmount, totalAmount } = bonusAmountMixin(
            challenge.completions,
            challenge.bonusCompletions
        );
        const bonusChallenge = {
            ...challenge,
            bonusCompletions: bonusAmount,
            totalCompletions: totalAmount
        } satisfies BonusChallenge;

        return bonusChallenge;
    });
}