demo
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import {useMemo, useState} from 'react'
|
import {useMemo, useState} from 'react'
|
||||||
import {type TextStyle, View, type ViewStyle} from 'react-native'
|
import {type TextStyle, View, type ViewStyle} from 'react-native'
|
||||||
|
import Animated, {
|
||||||
|
FadeIn,
|
||||||
|
FadeInDown,
|
||||||
|
FadeOut,
|
||||||
|
LinearTransition,
|
||||||
|
} from 'react-native-reanimated'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
@@ -46,20 +52,6 @@ export function InterestsSettingsScreen({}: Props) {
|
|||||||
</Layout.Header.Outer>
|
</Layout.Header.Outer>
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
<View style={[gutters, a.gap_lg]}>
|
<View style={[gutters, a.gap_lg]}>
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
a.flex_1,
|
|
||||||
a.text_sm,
|
|
||||||
a.leading_snug,
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
<Trans>
|
|
||||||
Your selected interests help us serve you content you care about.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{preferences ? (
|
{preferences ? (
|
||||||
<Inner preferences={preferences} setIsSaving={setIsSaving} />
|
<Inner preferences={preferences} setIsSaving={setIsSaving} />
|
||||||
) : (
|
) : (
|
||||||
@@ -73,96 +65,33 @@ export function InterestsSettingsScreen({}: Props) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Inner({
|
function Inner({}: {
|
||||||
preferences,
|
|
||||||
setIsSaving,
|
|
||||||
}: {
|
|
||||||
preferences: UsePreferencesQueryResponse
|
preferences: UsePreferencesQueryResponse
|
||||||
setIsSaving: (isSaving: boolean) => void
|
setIsSaving: (isSaving: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
|
||||||
const qc = useQueryClient()
|
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
const preselectedInterests = useMemo(
|
const [interests, setInterests] = useState<string[]>([])
|
||||||
() => preferences.interests.tags || [],
|
|
||||||
[preferences.interests.tags],
|
|
||||||
)
|
|
||||||
const [interests, setInterests] = useState<string[]>(preselectedInterests)
|
|
||||||
|
|
||||||
const saveInterests = useMemo(() => {
|
|
||||||
return debounce(async (interests: string[]) => {
|
|
||||||
const noEdits =
|
|
||||||
interests.length === preselectedInterests.length &&
|
|
||||||
preselectedInterests.every(pre => {
|
|
||||||
return interests.find(int => int === pre)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (noEdits) return
|
|
||||||
|
|
||||||
setIsSaving(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await agent.setInterestsPref({tags: interests})
|
|
||||||
qc.setQueriesData(
|
|
||||||
{queryKey: preferencesQueryKey},
|
|
||||||
(old?: UsePreferencesQueryResponse) => {
|
|
||||||
if (!old) return old
|
|
||||||
old.interests.tags = interests
|
|
||||||
return old
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await Promise.all([
|
|
||||||
qc.resetQueries({queryKey: createSuggestedStarterPacksQueryKey()}),
|
|
||||||
qc.resetQueries({queryKey: createGetSuggestedFeedsQueryKey()}),
|
|
||||||
qc.resetQueries({queryKey: createGetSuggestedUsersQueryKey({})}),
|
|
||||||
])
|
|
||||||
|
|
||||||
Toast.show(
|
|
||||||
_(
|
|
||||||
msg({
|
|
||||||
message: 'Your interests have been updated!',
|
|
||||||
context: 'toast',
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
Toast.show(
|
|
||||||
_(
|
|
||||||
msg({
|
|
||||||
message: 'Failed to save your interests.',
|
|
||||||
context: 'toast',
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
'xmark',
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
setIsSaving(false)
|
|
||||||
}
|
|
||||||
}, 1500)
|
|
||||||
}, [_, agent, setIsSaving, qc, preselectedInterests])
|
|
||||||
|
|
||||||
const onChangeInterests = async (interests: string[]) => {
|
const onChangeInterests = async (interests: string[]) => {
|
||||||
setInterests(interests)
|
setInterests(interests)
|
||||||
saveInterests(interests)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const additional = interests.filter(
|
||||||
|
interest =>
|
||||||
|
Object.keys(findRecursive(interest, INTERESTS) ?? {}).length > 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('react', findRecursive('react', INTERESTS))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{interests.length === 0 && (
|
|
||||||
<Admonition type="tip">
|
|
||||||
<Trans>We recommend selecting at least two interests.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Toggle.Group
|
<Toggle.Group
|
||||||
values={interests}
|
values={interests}
|
||||||
onChange={onChangeInterests}
|
onChange={onChangeInterests}
|
||||||
label={_(msg`Select your interests from the options below`)}>
|
label={_(msg`Select your interests from the options below`)}>
|
||||||
<View style={[a.flex_row, a.flex_wrap, a.gap_sm]}>
|
<View style={[a.flex_row, a.flex_wrap, a.gap_sm]}>
|
||||||
{INTERESTS.map(interest => {
|
{Object.keys(INTERESTS).map(interest => {
|
||||||
const name = interestsDisplayNames[interest]
|
|
||||||
if (!name) return null
|
|
||||||
return (
|
return (
|
||||||
<Toggle.Item
|
<Toggle.Item
|
||||||
key={interest}
|
key={interest}
|
||||||
@@ -173,6 +102,56 @@ function Inner({
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
|
{additional.map(interest => {
|
||||||
|
const found = findRecursive(interest, INTERESTS) ?? {}
|
||||||
|
console.log(interest)
|
||||||
|
console.log(found)
|
||||||
|
console.log(
|
||||||
|
interests.map(
|
||||||
|
interest => interest + findRecursive(interest, found),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
interests
|
||||||
|
.map(interest =>
|
||||||
|
Object.keys(findRecursive(interest, found) ?? {}),
|
||||||
|
)
|
||||||
|
.filter(x => Boolean(x) && x.length > 0)
|
||||||
|
.flat(),
|
||||||
|
)
|
||||||
|
const pills = [
|
||||||
|
...Object.keys(found),
|
||||||
|
...interests
|
||||||
|
.map(interest =>
|
||||||
|
Object.keys(findRecursive(interest, found) ?? {}),
|
||||||
|
)
|
||||||
|
.filter(x => Boolean(x) && x.length > 0)
|
||||||
|
.flat(),
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
key={interest}
|
||||||
|
style={[a.mt_xl]}
|
||||||
|
entering={FadeInDown}
|
||||||
|
exiting={FadeOut}
|
||||||
|
layout={LinearTransition.duration(100)}>
|
||||||
|
<Text style={[a.font_heavy, a.text_lg, a.mb_lg]}>{interest}</Text>
|
||||||
|
<View style={[a.flex_row, a.flex_wrap, a.gap_sm]}>
|
||||||
|
{pills.map((interest, index) => {
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
key={interest}
|
||||||
|
entering={FadeIn.delay(index * 100)}>
|
||||||
|
<Toggle.Item name={interest} label={interest}>
|
||||||
|
<InterestButton interest={interest} />
|
||||||
|
</Toggle.Item>
|
||||||
|
</Animated.View>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</Animated.View>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</Toggle.Group>
|
</Toggle.Group>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@@ -180,7 +159,6 @@ function Inner({
|
|||||||
|
|
||||||
export function InterestButton({interest}: {interest: string}) {
|
export function InterestButton({interest}: {interest: string}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
|
||||||
const ctx = Toggle.useItemContext()
|
const ctx = Toggle.useItemContext()
|
||||||
|
|
||||||
const styles = useMemo(() => {
|
const styles = useMemo(() => {
|
||||||
@@ -219,40 +197,91 @@ export function InterestButton({interest}: {interest: string}) {
|
|||||||
<Text
|
<Text
|
||||||
selectable={false}
|
selectable={false}
|
||||||
style={[
|
style={[
|
||||||
{
|
{color: t.palette.contrast_900},
|
||||||
color: t.palette.contrast_900,
|
|
||||||
},
|
|
||||||
a.font_bold,
|
a.font_bold,
|
||||||
ctx.selected ? styles.textSelected : {},
|
ctx.selected ? styles.textSelected : {},
|
||||||
]}>
|
]}>
|
||||||
{interestsDisplayNames[interest]}
|
{interest}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const INTERESTS = [
|
type Interests = Record<
|
||||||
'animals',
|
string,
|
||||||
'art',
|
{} | Record<string, {} | Record<string, {} | Record<string, {}>>>
|
||||||
'books',
|
>
|
||||||
'comedy',
|
|
||||||
'comics',
|
function findRecursive(
|
||||||
'culture',
|
interest: string,
|
||||||
'dev',
|
interests: Interests,
|
||||||
'education',
|
): Interests | null {
|
||||||
'food',
|
if (interests[interest]) return interests[interest]
|
||||||
'gaming',
|
for (const key in interests) {
|
||||||
'journalism',
|
const found = findRecursive(key, interests[key])
|
||||||
'movies',
|
if (found) return found
|
||||||
'music',
|
}
|
||||||
'nature',
|
return null
|
||||||
'news',
|
}
|
||||||
'pets',
|
|
||||||
'photography',
|
const INTERESTS = {
|
||||||
'politics',
|
animals: {},
|
||||||
'science',
|
art: {
|
||||||
'sports',
|
comics: {},
|
||||||
'tech',
|
illustration: {
|
||||||
'tv',
|
'digital art': {},
|
||||||
'writers',
|
'hand drawn': {},
|
||||||
]
|
'furry art': {},
|
||||||
|
},
|
||||||
|
painting: {
|
||||||
|
watercolor: {},
|
||||||
|
'fine art': {},
|
||||||
|
},
|
||||||
|
'fan art': {},
|
||||||
|
sculpture: {},
|
||||||
|
'art history': {},
|
||||||
|
},
|
||||||
|
books: {},
|
||||||
|
comedy: {},
|
||||||
|
culture: {},
|
||||||
|
dev: {
|
||||||
|
'web dev': {
|
||||||
|
design: {},
|
||||||
|
css: {},
|
||||||
|
react: {
|
||||||
|
'react native': {},
|
||||||
|
},
|
||||||
|
svelte: {},
|
||||||
|
typescript: {},
|
||||||
|
},
|
||||||
|
'game dev': {},
|
||||||
|
atproto: {},
|
||||||
|
},
|
||||||
|
education: {},
|
||||||
|
food: {},
|
||||||
|
gaming: {},
|
||||||
|
journalism: {},
|
||||||
|
movies: {},
|
||||||
|
music: {},
|
||||||
|
nature: {},
|
||||||
|
news: {},
|
||||||
|
pets: {
|
||||||
|
cats: {},
|
||||||
|
dogs: {},
|
||||||
|
birds: {
|
||||||
|
parrots: {},
|
||||||
|
canaries: {},
|
||||||
|
finches: {},
|
||||||
|
},
|
||||||
|
fish: {},
|
||||||
|
reptiles: {},
|
||||||
|
bunnies: {},
|
||||||
|
},
|
||||||
|
photography: {},
|
||||||
|
politics: {},
|
||||||
|
science: {},
|
||||||
|
sports: {},
|
||||||
|
tech: {},
|
||||||
|
tv: {},
|
||||||
|
writers: {},
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user