mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {GestureResponderEvent, View} from 'react-native'
3import {msg} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {atoms as a, useBreakpoints, useTheme} from '#/alf'
7import {Button, ButtonColor, ButtonProps, ButtonText} from '#/components/Button'
8import * as Dialog from '#/components/Dialog'
9import {Text} from '#/components/Typography'
10
11export {
12 type DialogControlProps as PromptControlProps,
13 useDialogControl as usePromptControl,
14} from '#/components/Dialog'
15
16const Context = React.createContext<{
17 titleId: string
18 descriptionId: string
19}>({
20 titleId: '',
21 descriptionId: '',
22})
23
24export function Outer({
25 children,
26 control,
27 testID,
28}: React.PropsWithChildren<{
29 control: Dialog.DialogControlProps
30 testID?: string
31}>) {
32 const {gtMobile} = useBreakpoints()
33 const titleId = React.useId()
34 const descriptionId = React.useId()
35
36 const context = React.useMemo(
37 () => ({titleId, descriptionId}),
38 [titleId, descriptionId],
39 )
40
41 return (
42 <Dialog.Outer control={control} testID={testID}>
43 <Context.Provider value={context}>
44 <Dialog.Handle />
45
46 <Dialog.ScrollableInner
47 accessibilityLabelledBy={titleId}
48 accessibilityDescribedBy={descriptionId}
49 style={[
50 gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
51 ]}>
52 {children}
53 </Dialog.ScrollableInner>
54 </Context.Provider>
55 </Dialog.Outer>
56 )
57}
58
59export function TitleText({children}: React.PropsWithChildren<{}>) {
60 const {titleId} = React.useContext(Context)
61 return (
62 <Text nativeID={titleId} style={[a.text_2xl, a.font_bold, a.pb_sm]}>
63 {children}
64 </Text>
65 )
66}
67
68export function DescriptionText({
69 children,
70 selectable,
71}: React.PropsWithChildren<{selectable?: boolean}>) {
72 const t = useTheme()
73 const {descriptionId} = React.useContext(Context)
74 return (
75 <Text
76 nativeID={descriptionId}
77 selectable={selectable}
78 style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high, a.pb_lg]}>
79 {children}
80 </Text>
81 )
82}
83
84export function Actions({children}: React.PropsWithChildren<{}>) {
85 const {gtMobile} = useBreakpoints()
86
87 return (
88 <View
89 style={[
90 a.w_full,
91 a.gap_md,
92 a.justify_end,
93 gtMobile
94 ? [a.flex_row, a.flex_row_reverse, a.justify_start]
95 : [a.flex_col],
96 ]}>
97 {children}
98 </View>
99 )
100}
101
102export function Cancel({
103 cta,
104}: {
105 /**
106 * Optional i18n string. If undefined, it will default to "Cancel".
107 */
108 cta?: string
109}) {
110 const {_} = useLingui()
111 const {gtMobile} = useBreakpoints()
112 const {close} = Dialog.useDialogContext()
113 const onPress = React.useCallback(() => {
114 close()
115 }, [close])
116
117 return (
118 <Button
119 variant="solid"
120 color="secondary"
121 size={gtMobile ? 'small' : 'medium'}
122 label={cta || _(msg`Cancel`)}
123 onPress={onPress}>
124 <ButtonText>{cta || _(msg`Cancel`)}</ButtonText>
125 </Button>
126 )
127}
128
129export function Action({
130 onPress,
131 color = 'primary',
132 cta,
133 testID,
134}: {
135 /**
136 * Callback to run when the action is pressed. The method is called _after_
137 * the dialog closes.
138 *
139 * Note: The dialog will close automatically when the action is pressed, you
140 * should NOT close the dialog as a side effect of this method.
141 */
142 onPress: ButtonProps['onPress']
143 color?: ButtonColor
144 /**
145 * Optional i18n string. If undefined, it will default to "Confirm".
146 */
147 cta?: string
148 testID?: string
149}) {
150 const {_} = useLingui()
151 const {gtMobile} = useBreakpoints()
152 const {close} = Dialog.useDialogContext()
153 const handleOnPress = React.useCallback(
154 (e: GestureResponderEvent) => {
155 close(() => onPress?.(e))
156 },
157 [close, onPress],
158 )
159
160 return (
161 <Button
162 variant="solid"
163 color={color}
164 size={gtMobile ? 'small' : 'medium'}
165 label={cta || _(msg`Confirm`)}
166 onPress={handleOnPress}
167 testID={testID}>
168 <ButtonText>{cta || _(msg`Confirm`)}</ButtonText>
169 </Button>
170 )
171}
172
173export function Basic({
174 control,
175 title,
176 description,
177 cancelButtonCta,
178 confirmButtonCta,
179 onConfirm,
180 confirmButtonColor,
181 showCancel = true,
182}: React.PropsWithChildren<{
183 control: Dialog.DialogOuterProps['control']
184 title: string
185 description: string
186 cancelButtonCta?: string
187 confirmButtonCta?: string
188 /**
189 * Callback to run when the Confirm button is pressed. The method is called
190 * _after_ the dialog closes.
191 *
192 * Note: The dialog will close automatically when the action is pressed, you
193 * should NOT close the dialog as a side effect of this method.
194 */
195 onConfirm: ButtonProps['onPress']
196 confirmButtonColor?: ButtonColor
197 showCancel?: boolean
198}>) {
199 return (
200 <Outer control={control} testID="confirmModal">
201 <TitleText>{title}</TitleText>
202 <DescriptionText>{description}</DescriptionText>
203 <Actions>
204 <Action
205 cta={confirmButtonCta}
206 onPress={onConfirm}
207 color={confirmButtonColor}
208 testID="confirmBtn"
209 />
210 {showCancel && <Cancel cta={cancelButtonCta} />}
211 </Actions>
212 </Outer>
213 )
214}