diff --git a/app/challenges/[id]/index.tsx b/app/challenges/[id]/index.tsx
index 8e07a3e..f72e5a8 100644
--- a/app/challenges/[id]/index.tsx
+++ b/app/challenges/[id]/index.tsx
@@ -595,7 +595,7 @@ export default function ChallengeDetailScreen() {
- {challenge.requirementLabel}
+ {challenge.requirementLabel ? {challenge.requirementLabel} : null}
{t('challengeDetail.shareCard.info.checkInDaily')}
@@ -743,7 +743,7 @@ export default function ChallengeDetailScreen() {
- {challenge.requirementLabel}
+ {challenge.requirementLabel ? {challenge.requirementLabel} : null}
{t('challengeDetail.detail.requirement')}
diff --git a/app/challenges/create-custom.tsx b/app/challenges/create-custom.tsx
index 9e093af..12c72de 100644
--- a/app/challenges/create-custom.tsx
+++ b/app/challenges/create-custom.tsx
@@ -1,3 +1,4 @@
+import i18n from '@/i18n';
import dayjs from 'dayjs';
import { BlurView } from 'expo-blur';
import * as Clipboard from 'expo-clipboard';
@@ -53,6 +54,7 @@ const getTypeOptions = (t: (key: string) => string): { value: ChallengeType; lab
{ value: ChallengeType.SLEEP, label: t('challenges.createCustom.typeLabels.sleep'), accent: '#7C3AED' },
{ value: ChallengeType.MOOD, label: t('challenges.createCustom.typeLabels.mood'), accent: '#F97316' },
{ value: ChallengeType.WEIGHT, label: t('challenges.createCustom.typeLabels.weight'), accent: '#22C55E' },
+ { value: ChallengeType.CUSTOM, label: t('challenges.createCustom.typeLabels.custom'), accent: '#8B5CF6' },
];
const FALLBACK_IMAGE =
@@ -97,7 +99,7 @@ export default function CreateCustomChallengeScreen() {
const [progressUnit, setProgressUnit] = useState('');
const [periodLabel, setPeriodLabel] = useState('');
const [periodEdited, setPeriodEdited] = useState(false);
- const [rankingDescription] = useState('连续打卡榜');
+ const [rankingDescription] = useState(t('challenges.createCustom.rankingDescription'));
const [isPublic, setIsPublic] = useState(true);
const [maxParticipants, setMaxParticipants] = useState('100');
const [minimumEdited, setMinimumEdited] = useState(false);
@@ -121,7 +123,6 @@ export default function CreateCustomChallengeScreen() {
setEndDate(new Date(challenge.endAt || Date.now()));
setTargetValue(String(challenge.progress?.target || ''));
setMinimumCheckInDays(String(challenge.minimumCheckInDays || ''));
- setRequirementLabel(challenge.requirementLabel || '');
setSummary(challenge.summary || '');
setProgressUnit(challenge.unit || '');
setPeriodLabel(challenge.periodLabel || '');
@@ -177,10 +178,6 @@ export default function CreateCustomChallengeScreen() {
return;
}
- if (!requirementLabel.trim()) {
- Toast.warning(t('challenges.createCustom.alerts.requirementRequired'));
- return;
- }
const startTimestamp = dayjs(startDate).valueOf();
const endTimestamp = dayjs(endDate).valueOf();
@@ -221,7 +218,7 @@ export default function CreateCustomChallengeScreen() {
targetValue: target,
minimumCheckInDays: minDays,
durationLabel,
- requirementLabel: requirementLabel.trim(),
+ requirementLabel: '',
summary: summary.trim() || undefined,
progressUnit: progressUnit.trim(),
periodLabel: periodLabel.trim() || undefined,
@@ -513,16 +510,19 @@ export default function CreateCustomChallengeScreen() {
setType(option.value)}
+ onPress={() => !isEditMode && setType(option.value)}
+ disabled={isEditMode}
style={[
styles.chip,
active && { backgroundColor: `${option.accent}1A`, borderColor: option.accent },
+ isEditMode && styles.chipDisabled,
]}
>
{option.label}
@@ -531,6 +531,7 @@ export default function CreateCustomChallengeScreen() {
);
})}
+ {t('challenges.createCustom.fields.challengeTypeHelper')}
@@ -592,7 +593,6 @@ export default function CreateCustomChallengeScreen() {
{renderField(t('challenges.createCustom.fields.minimumCheckInDays'), minimumCheckInDays, handleMinimumDaysChange, t('challenges.createCustom.fields.minimumCheckInDaysPlaceholder'), 'numeric')}
- {renderField(t('challenges.createCustom.fields.challengeRequirement'), requirementLabel, setRequirementLabel, t('challenges.createCustom.fields.requirementPlaceholder'))}
@@ -675,6 +675,9 @@ export default function CreateCustomChallengeScreen() {
minimumDate={pickerType === 'end' ? dayjs(startDate).add(1, 'day').toDate() : dayjs().add(1, 'day').toDate()}
onConfirm={handleConfirmDate}
onCancel={() => setPickerType(null)}
+ locale={i18n.language}
+ confirmTextIOS={t('challenges.createCustom.datePicker.confirm')}
+ cancelTextIOS={t('challenges.createCustom.datePicker.cancel')}
/>