Skip to content

Commit

Permalink
feat: Inline price control create alert (#8835)
Browse files Browse the repository at this point in the history
* inline price control create alert

* update

* revert podlock file

* new screen

* with Edit Alert flow

* price update

* remove section

* updated  with PR

* AlertPriceRangeScreen to AlertPriceRange
  • Loading branch information
Sam Raj authored Jun 20, 2023
1 parent 50465dc commit 707a3b4
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 93 deletions.
31 changes: 30 additions & 1 deletion src/app/Scenes/SavedSearchAlert/Components/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { CloseIcon, Spacer, Flex, Box, Text, Button } from "@artsy/palette-mobile"
import {
CloseIcon,
Spacer,
Flex,
Box,
Text,
Button,
ArrowRightIcon,
Touchable,
} from "@artsy/palette-mobile"
import { NavigationProp, useNavigation } from "@react-navigation/native"
import { SearchCriteria } from "app/Components/ArtworkFilter/SavedSearch/types"
import { Input, InputTitle } from "app/Components/Input"
import { Pill } from "app/Components/Pill"
import {
CreateSavedSearchAlertNavigationStack,
SavedSearchAlertFormValues,
SavedSearchPill,
} from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel"
Expand Down Expand Up @@ -41,6 +52,8 @@ export const Form: React.FC<FormProps> = (props) => {
} = props
const { isSubmitting, values, errors, dirty, handleBlur, handleChange } =
useFormikContext<SavedSearchAlertFormValues>()
const navigation =
useNavigation<NavigationProp<CreateSavedSearchAlertNavigationStack, "CreateSavedSearchAlert">>()
const entity = SavedSearchStore.useStoreState((state) => state.entity)
const isEditMode = !!savedSearchAlertId
let isSaveAlertButtonDisabled = false
Expand Down Expand Up @@ -125,6 +138,22 @@ export const Form: React.FC<FormProps> = (props) => {
))}
</Flex>
</Box>
<Spacer y={2} />
<Touchable
accessibilityLabel="Set price range"
accessibilityRole="button"
onPress={() => navigation.navigate("AlertPriceRange")}
>
<Flex flexDirection="row" alignItems="center" py={1}>
<Flex flex={1}>
<Text variant="sm-display">Set price range you are interested in</Text>
</Flex>
<Flex alignSelf="center" mt={0.5}>
<ArrowRightIcon />
</Flex>
</Flex>
</Touchable>
<Spacer y={4} />
<SavedSearchAlertSwitch
label="Mobile Alerts"
onChange={onTogglePushNotification}
Expand Down
63 changes: 40 additions & 23 deletions src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,58 @@
import { Box } from "@artsy/palette-mobile"
import { NavigationContainer } from "@react-navigation/native"
import { createStackNavigator, TransitionPresets } from "@react-navigation/stack"
import { SearchCriteriaAttributes } from "app/Components/ArtworkFilter/SavedSearch/types"
import { FancyModal } from "app/Components/FancyModal/FancyModal"
import {
savedSearchModel,
SavedSearchStoreProvider,
} from "app/Scenes/SavedSearchAlert/SavedSearchStore"
import { CreateSavedSearchAlertContentQueryRenderer } from "app/Scenes/SavedSearchAlert/containers/CreateSavedSearchContentContainer"
import { AlertPriceRangeScreen } from "app/Scenes/SavedSearchAlert/screens/AlertPriceRangeScreen"
import {
CreateSavedSearchAlertNavigationStack,
CreateSavedSearchAlertProps,
} from "./SavedSearchAlertModel"
import { CreateSavedSearchAlertScreen } from "./screens/CreateSavedSearchAlertScreen"
import { EmailPreferencesScreen } from "./screens/EmailPreferencesScreen"

const Stack = createStackNavigator<CreateSavedSearchAlertNavigationStack>()

export const CreateSavedSearchAlert: React.FC<CreateSavedSearchAlertProps> = (props) => {
const { visible, params } = props
const { attributes, aggregations, entity } = params

return (
<NavigationContainer independent>
<FancyModal visible={visible} fullScreen>
<Box flex={1}>
<Stack.Navigator
// force it to not use react-native-screens, which is broken inside a react-native Modal for some reason
detachInactiveScreens={false}
screenOptions={{
...TransitionPresets.SlideFromRightIOS,
headerShown: false,
cardStyle: { backgroundColor: "white" },
}}
>
<Stack.Screen
name="CreateSavedSearchAlert"
component={CreateSavedSearchAlertScreen}
initialParams={params}
/>
<Stack.Screen name="EmailPreferences" component={EmailPreferencesScreen} />
</Stack.Navigator>
</Box>
</FancyModal>
</NavigationContainer>
<SavedSearchStoreProvider
runtimeModel={{
...savedSearchModel,
attributes: attributes as SearchCriteriaAttributes,
aggregations,
entity,
}}
>
<NavigationContainer independent>
<FancyModal visible={visible} fullScreen>
<Box flex={1}>
<Stack.Navigator
// force it to not use react-native-screens, which is broken inside a react-native Modal for some reason
detachInactiveScreens={false}
screenOptions={{
...TransitionPresets.SlideFromRightIOS,
headerShown: false,
cardStyle: { backgroundColor: "white" },
}}
>
<Stack.Screen
name="CreateSavedSearchAlert"
component={CreateSavedSearchAlertContentQueryRenderer}
initialParams={params}
/>
<Stack.Screen name="EmailPreferences" component={EmailPreferencesScreen} />
<Stack.Screen name="AlertPriceRange" component={AlertPriceRangeScreen} />
</Stack.Navigator>
</Box>
</FancyModal>
</NavigationContainer>
</SavedSearchStoreProvider>
)
}
69 changes: 46 additions & 23 deletions src/app/Scenes/SavedSearchAlert/EditSavedSearchAlert.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { OwnerType } from "@artsy/cohesion"
import { NavigationContainer } from "@react-navigation/native"
import { TransitionPresets, createStackNavigator } from "@react-navigation/stack"
import { EditSavedSearchAlertQuery } from "__generated__/EditSavedSearchAlertQuery.graphql"
import { EditSavedSearchAlert_artists$data } from "__generated__/EditSavedSearchAlert_artists.graphql"
import { EditSavedSearchAlert_artworksConnection$data } from "__generated__/EditSavedSearchAlert_artworksConnection.graphql"
Expand All @@ -10,7 +12,13 @@ import {
SavedSearchEntityArtist,
SearchCriteriaAttributes,
} from "app/Components/ArtworkFilter/SavedSearch/types"
import { PageWithSimpleHeader } from "app/Components/PageWithSimpleHeader"
import { EditSavedSearchAlertContent } from "app/Scenes/SavedSearchAlert/EditSavedSearchAlertContent"
import {
EditSavedSearchAlertNavigationStack,
EditSavedSearchAlertParams,
} from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel"
import { AlertPriceRangeScreen } from "app/Scenes/SavedSearchAlert/screens/AlertPriceRangeScreen"
import { EmailPreferencesScreen } from "app/Scenes/SavedSearchAlert/screens/EmailPreferencesScreen"
import { goBack, GoBackProps, navigationEvents } from "app/system/navigation/navigate"
import { getRelayEnvironment } from "app/system/relay/defaultEnvironment"
import { ArtsyKeyboardAvoidingView } from "app/utils/ArtsyKeyboardAvoidingView"
Expand All @@ -20,7 +28,6 @@ import React, { useCallback, useEffect } from "react"
import { createRefetchContainer, graphql, QueryRenderer, RelayRefetchProp } from "react-relay"
import { EditSavedSearchFormPlaceholder } from "./Components/EditSavedSearchAlertPlaceholder"
import { SavedSearchAlertQueryRenderer } from "./SavedSearchAlert"
import { SavedSearchAlertForm } from "./SavedSearchAlertForm"
import { SavedSearchStoreProvider, savedSearchModel } from "./SavedSearchStore"

interface EditSavedSearchAlertBaseProps {
Expand All @@ -36,6 +43,8 @@ interface EditSavedSearchAlertProps {
relay: RelayRefetchProp
}

const Stack = createStackNavigator<EditSavedSearchAlertNavigationStack>()

export const EditSavedSearchAlert: React.FC<EditSavedSearchAlertProps> = (props) => {
const { me, viewer, artists, artworksConnection, savedSearchAlertId, relay } = props
const aggregations = (artworksConnection.aggregations ?? []) as Aggregations
Expand Down Expand Up @@ -86,6 +95,14 @@ export const EditSavedSearchAlert: React.FC<EditSavedSearchAlertProps> = (props)
}
}, [])

const params: EditSavedSearchAlertParams = {
userAlertSettings,
savedSearchAlertId,
userAllowsEmails,
onComplete,
onDeleteComplete: onComplete,
}

return (
<ProvideScreenTracking
info={{
Expand All @@ -95,28 +112,34 @@ export const EditSavedSearchAlert: React.FC<EditSavedSearchAlertProps> = (props)
}}
>
<ArtsyKeyboardAvoidingView>
<PageWithSimpleHeader title="Edit your Alert">
<SavedSearchStoreProvider
runtimeModel={{
...savedSearchModel,
attributes: attributes as SearchCriteriaAttributes,
aggregations,
entity,
}}
>
<SavedSearchAlertForm
initialValues={{
name: userAlertSettings?.name ?? "",
email: userAlertSettings?.email ?? false,
push: userAlertSettings?.push ?? false,
<SavedSearchStoreProvider
runtimeModel={{
...savedSearchModel,
attributes: attributes as SearchCriteriaAttributes,
aggregations,
entity,
}}
>
<NavigationContainer independent>
<Stack.Navigator
// force it to not use react-native-screens, which is broken inside a react-native Modal for some reason
detachInactiveScreens={false}
screenOptions={{
...TransitionPresets.SlideFromRightIOS,
headerShown: false,
cardStyle: { backgroundColor: "white" },
}}
savedSearchAlertId={savedSearchAlertId}
userAllowsEmails={userAllowsEmails}
onComplete={onComplete}
onDeleteComplete={onComplete}
/>
</SavedSearchStoreProvider>
</PageWithSimpleHeader>
>
<Stack.Screen
name="EditSavedSearchAlertContent"
component={EditSavedSearchAlertContent}
initialParams={params}
/>
<Stack.Screen name="EmailPreferences" component={EmailPreferencesScreen} />
<Stack.Screen name="AlertPriceRange" component={AlertPriceRangeScreen} />
</Stack.Navigator>
</NavigationContainer>
</SavedSearchStoreProvider>
</ArtsyKeyboardAvoidingView>
</ProvideScreenTracking>
)
Expand Down
27 changes: 27 additions & 0 deletions src/app/Scenes/SavedSearchAlert/EditSavedSearchAlertContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RouteProp, useRoute } from "@react-navigation/native"
import { PageWithSimpleHeader } from "app/Components/PageWithSimpleHeader"
import { SavedSearchAlertForm } from "app/Scenes/SavedSearchAlert/SavedSearchAlertForm"
import { EditSavedSearchAlertNavigationStack } from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel"

export const EditSavedSearchAlertContent = () => {
const route =
useRoute<RouteProp<EditSavedSearchAlertNavigationStack, "EditSavedSearchAlertContent">>()
const { userAlertSettings, savedSearchAlertId, userAllowsEmails, onComplete, onDeleteComplete } =
route.params

return (
<PageWithSimpleHeader title="Edit your Alert">
<SavedSearchAlertForm
initialValues={{
name: userAlertSettings?.name ?? "",
email: userAlertSettings?.email ?? false,
push: userAlertSettings?.push ?? false,
}}
savedSearchAlertId={savedSearchAlertId}
userAllowsEmails={userAllowsEmails}
onComplete={onComplete}
onDeleteComplete={onDeleteComplete}
/>
</PageWithSimpleHeader>
)
}
19 changes: 19 additions & 0 deletions src/app/Scenes/SavedSearchAlert/SavedSearchAlertModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ export interface CreateSavedSearchAlertProps {

export type CreateSavedSearchAlertNavigationStack = {
CreateSavedSearchAlert: CreateSavedSearchAlertParams
AlertPriceRange: undefined
EmailPreferences: undefined
}

export interface EditSavedSearchAlertParams {
userAlertSettings?: {
name: string | null
email: boolean
push: boolean
}
savedSearchAlertId?: string
userAllowsEmails: boolean
onComplete?: (result: SavedSearchAlertMutationResult) => void
onDeleteComplete?: () => void
}

export type EditSavedSearchAlertNavigationStack = {
EditSavedSearchAlertContent: EditSavedSearchAlertParams
AlertPriceRange: undefined
EmailPreferences: undefined
}

Expand Down
21 changes: 21 additions & 0 deletions src/app/Scenes/SavedSearchAlert/SavedSearchStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ interface SavedSearchModel {
entity: SavedSearchEntity
dirty: boolean

setValueToAttributesByKeyAction: Action<
this,
{
key: SearchCriteria
value: string | null
}
>
removeValueFromAttributesByKeyAction: Action<
this,
{
Expand All @@ -36,6 +43,20 @@ export const savedSearchModel: SavedSearchModel = {
},
},

setValueToAttributesByKeyAction: action((state, payload) => {
if (payload.key === "priceRange") {
// set form dirty on price update
if (state.attributes[payload.key] !== payload.value) {
state.dirty = true
}

// set the price range to be null if the value is *-* (which means empty)
state.attributes[payload.key] = payload.value === "*-*" ? null : payload.value
} else {
state.attributes[payload.key] = payload.value as unknown as null | undefined
}
}),

removeValueFromAttributesByKeyAction: action((state, payload) => {
const prevValue = state.attributes[payload.key]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { Box } from "@artsy/palette-mobile"
import { useFocusEffect } from "@react-navigation/core"
import { StackNavigationProp } from "@react-navigation/stack"
import { NavigationProp, RouteProp, useNavigation, useRoute } from "@react-navigation/native"
import { captureMessage } from "@sentry/react-native"
import { CreateSavedSearchContentContainerQuery } from "__generated__/CreateSavedSearchContentContainerQuery.graphql"
import { CreateSavedSearchContentContainer_viewer$data } from "__generated__/CreateSavedSearchContentContainer_viewer.graphql"
import { FancyModalHeader } from "app/Components/FancyModal/FancyModalHeader"
import { SavedSearchAlertForm } from "app/Scenes/SavedSearchAlert/SavedSearchAlertForm"
import {
CreateSavedSearchAlertNavigationStack,
SavedSearchAlertMutationResult,
} from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel"
import { CreateSavedSearchAlertNavigationStack } from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel"
import { getRelayEnvironment } from "app/system/relay/defaultEnvironment"
import {
getNotificationPermissionsStatus,
Expand All @@ -19,21 +16,19 @@ import useAppState from "app/utils/useAppState"
import React, { useCallback, useEffect, useRef, useState } from "react"
import { createRefetchContainer, graphql, QueryRenderer, RelayRefetchProp } from "react-relay"

interface CreateSavedSearchAlertContentQueryRendererProps {
navigation: StackNavigationProp<CreateSavedSearchAlertNavigationStack, "CreateSavedSearchAlert">
onClosePress: () => void
onComplete: (response: SavedSearchAlertMutationResult) => void
}

interface CreateSavedSearchAlertContentProps
extends CreateSavedSearchAlertContentQueryRendererProps {
interface CreateSavedSearchAlertContentProps {
relay: RelayRefetchProp
viewer?: CreateSavedSearchContentContainer_viewer$data | null
loading: boolean
}

const CreateSavedSearchAlertContent: React.FC<CreateSavedSearchAlertContentProps> = (props) => {
const { viewer, loading, relay, navigation, onClosePress, ...other } = props
const navigation =
useNavigation<NavigationProp<CreateSavedSearchAlertNavigationStack, "CreateSavedSearchAlert">>()
const route =
useRoute<RouteProp<CreateSavedSearchAlertNavigationStack, "CreateSavedSearchAlert">>()
const { viewer, loading, relay } = props
const { onClosePress, ...other } = route.params
const isPreviouslyFocused = useRef(false)
const [refetching, setRefetching] = useState(false)
const [enablePushNotifications, setEnablePushNotifications] = useState(true)
Expand Down Expand Up @@ -125,7 +120,7 @@ const CreateSavedSearchContentContainer = createRefetchContainer(
)

export const CreateSavedSearchAlertContentQueryRenderer: React.FC<
CreateSavedSearchAlertContentQueryRendererProps
CreateSavedSearchAlertContentProps
> = (props) => {
return (
<QueryRenderer<CreateSavedSearchContentContainerQuery>
Expand Down
Loading

0 comments on commit 707a3b4

Please sign in to comment.