@planningcenter/chat-react-native 3.16.0-rc.4 → 3.16.0-rc.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/build/components/conversation/message.js +1 -1
  2. package/build/components/conversation/message.js.map +1 -1
  3. package/build/contexts/chat_context.d.ts +3 -0
  4. package/build/contexts/chat_context.d.ts.map +1 -1
  5. package/build/contexts/chat_context.js +3 -1
  6. package/build/contexts/chat_context.js.map +1 -1
  7. package/build/hooks/index.d.ts +3 -0
  8. package/build/hooks/index.d.ts.map +1 -1
  9. package/build/hooks/index.js +3 -0
  10. package/build/hooks/index.js.map +1 -1
  11. package/build/hooks/use_current_person.d.ts.map +1 -1
  12. package/build/hooks/use_current_person.js +9 -1
  13. package/build/hooks/use_current_person.js.map +1 -1
  14. package/build/hooks/use_organization.d.ts +39 -0
  15. package/build/hooks/use_organization.d.ts.map +1 -0
  16. package/build/hooks/use_organization.js +14 -0
  17. package/build/hooks/use_organization.js.map +1 -0
  18. package/build/hooks/use_qualified_by_age.d.ts +2 -0
  19. package/build/hooks/use_qualified_by_age.d.ts.map +1 -0
  20. package/build/hooks/use_qualified_by_age.js +14 -0
  21. package/build/hooks/use_qualified_by_age.js.map +1 -0
  22. package/build/hooks/use_submit_age_check.d.ts +78 -0
  23. package/build/hooks/use_submit_age_check.d.ts.map +1 -0
  24. package/build/hooks/use_submit_age_check.js +37 -0
  25. package/build/hooks/use_submit_age_check.js.map +1 -0
  26. package/build/index.d.ts +1 -0
  27. package/build/index.d.ts.map +1 -1
  28. package/build/index.js +1 -0
  29. package/build/index.js.map +1 -1
  30. package/build/navigation/chat_access_gate.d.ts +3 -0
  31. package/build/navigation/chat_access_gate.d.ts.map +1 -0
  32. package/build/navigation/chat_access_gate.js +46 -0
  33. package/build/navigation/chat_access_gate.js.map +1 -0
  34. package/build/navigation/index.d.ts +6 -4
  35. package/build/navigation/index.d.ts.map +1 -1
  36. package/build/navigation/index.js +6 -3
  37. package/build/navigation/index.js.map +1 -1
  38. package/build/navigation/screenLayout.d.ts +3 -0
  39. package/build/navigation/screenLayout.d.ts.map +1 -1
  40. package/build/navigation/screenLayout.js +8 -0
  41. package/build/navigation/screenLayout.js.map +1 -1
  42. package/build/screens/age_check/age_check_required_screen.d.ts +3 -0
  43. package/build/screens/age_check/age_check_required_screen.d.ts.map +1 -0
  44. package/build/screens/age_check/age_check_required_screen.js +148 -0
  45. package/build/screens/age_check/age_check_required_screen.js.map +1 -0
  46. package/build/screens/age_check/age_check_underage_screen.d.ts +6 -0
  47. package/build/screens/age_check/age_check_underage_screen.d.ts.map +1 -0
  48. package/build/screens/age_check/age_check_underage_screen.js +71 -0
  49. package/build/screens/age_check/age_check_underage_screen.js.map +1 -0
  50. package/build/screens/age_check/components/age_check_select_birthdate_modal.d.ts +11 -0
  51. package/build/screens/age_check/components/age_check_select_birthdate_modal.d.ts.map +1 -0
  52. package/build/screens/age_check/components/age_check_select_birthdate_modal.js +91 -0
  53. package/build/screens/age_check/components/age_check_select_birthdate_modal.js.map +1 -0
  54. package/build/screens/age_check/index.d.ts +3 -0
  55. package/build/screens/age_check/index.d.ts.map +1 -0
  56. package/build/screens/age_check/index.js +3 -0
  57. package/build/screens/age_check/index.js.map +1 -0
  58. package/build/screens/age_check/screen_props.d.ts +5 -0
  59. package/build/screens/age_check/screen_props.d.ts.map +1 -0
  60. package/build/screens/age_check/screen_props.js +2 -0
  61. package/build/screens/age_check/screen_props.js.map +1 -0
  62. package/build/types/resources/index.d.ts +1 -0
  63. package/build/types/resources/index.d.ts.map +1 -1
  64. package/build/types/resources/index.js +1 -0
  65. package/build/types/resources/index.js.map +1 -1
  66. package/build/types/resources/organization.d.ts +6 -0
  67. package/build/types/resources/organization.d.ts.map +1 -0
  68. package/build/types/resources/organization.js +2 -0
  69. package/build/types/resources/organization.js.map +1 -0
  70. package/build/types/resources/person.d.ts +7 -0
  71. package/build/types/resources/person.d.ts.map +1 -1
  72. package/build/types/resources/person.js +5 -1
  73. package/build/types/resources/person.js.map +1 -1
  74. package/package.json +3 -2
  75. package/src/components/conversation/message.tsx +1 -1
  76. package/src/contexts/chat_context.tsx +14 -1
  77. package/src/hooks/index.ts +3 -0
  78. package/src/hooks/use_current_person.ts +9 -1
  79. package/src/hooks/use_organization.ts +17 -0
  80. package/src/hooks/use_qualified_by_age.ts +17 -0
  81. package/src/hooks/use_submit_age_check.ts +48 -0
  82. package/src/index.tsx +1 -0
  83. package/src/navigation/chat_access_gate.tsx +60 -0
  84. package/src/navigation/index.tsx +6 -3
  85. package/src/navigation/screenLayout.tsx +11 -0
  86. package/src/screens/age_check/age_check_required_screen.tsx +197 -0
  87. package/src/screens/age_check/age_check_underage_screen.tsx +96 -0
  88. package/src/screens/age_check/components/age_check_select_birthdate_modal.tsx +143 -0
  89. package/src/screens/age_check/index.ts +2 -0
  90. package/src/screens/age_check/screen_props.ts +3 -0
  91. package/src/types/resources/index.ts +1 -0
  92. package/src/types/resources/organization.ts +6 -0
  93. package/src/types/resources/person.ts +10 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age_check_select_birthdate_modal.js","sourceRoot":"","sources":["../../../../src/screens/age_check/components/age_check_select_birthdate_modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { Modal, Platform, StyleSheet, View } from 'react-native'\nimport DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker'\nimport FormSheet from '../../../components/primitive/form_sheet'\nimport { Text } from '../../../components/display/text'\nimport { useTheme } from '../../../hooks'\n\nexport type AgeCheckSelectBirthdateProps = {\n onChange: (date: Date) => void\n onDismiss?: () => void\n onRequestClose: () => void\n onSubmit: (date: Date) => void\n value?: Date | null\n visible?: boolean\n}\n\nexport function AgeCheckSelectBirthdateModal(props: AgeCheckSelectBirthdateProps) {\n if (Platform.OS === 'ios') return <IOSBirthdateModal {...props} />\n if (Platform.OS === 'android') return <AndroidBirthdatePicker {...props} />\n\n return <Text>Birthdate selection is not supported on this platform.</Text>\n}\n\nfunction IOSBirthdateModal({\n onChange,\n onDismiss,\n onRequestClose,\n onSubmit,\n value,\n visible,\n}: AgeCheckSelectBirthdateProps) {\n const styles = useStyles()\n const today = React.useMemo(() => new Date(), [])\n const selected = value || today\n\n const handleChange = (_event: DateTimePickerEvent, date?: Date) => {\n if (date) onChange(date)\n }\n\n const handleSave = () => {\n onSubmit(selected)\n onRequestClose()\n }\n\n return (\n <Modal\n visible={visible}\n animationType=\"slide\"\n presentationStyle=\"pageSheet\"\n onRequestClose={onRequestClose}\n onDismiss={onDismiss}\n >\n <FormSheet.Root style={styles.formSheet} contentStyle={styles.formSheetContent}>\n <FormSheet.Header>\n <FormSheet.HeaderTitle>Your birthdate</FormSheet.HeaderTitle>\n <FormSheet.HeaderActions>\n <FormSheet.HeaderTextButton onPress={onRequestClose}>Cancel</FormSheet.HeaderTextButton>\n <FormSheet.HeaderButton title=\"Save\" onPress={handleSave} />\n </FormSheet.HeaderActions>\n </FormSheet.Header>\n <View style={styles.content}>\n <View style={styles.card}>\n <Text nativeID=\"birthdateLabel\" variant=\"tertiary\" style={styles.label}>\n Birthdate\n </Text>\n <View style={styles.pickerContainer}>\n <DateTimePicker\n accessibilityLabelledBy=\"birthdateLabel\"\n testID=\"age-check-date-picker\"\n mode=\"date\"\n display=\"spinner\"\n value={selected}\n maximumDate={today}\n onChange={handleChange}\n />\n </View>\n </View>\n </View>\n </FormSheet.Root>\n </Modal>\n )\n}\n\nfunction AndroidBirthdatePicker({\n onRequestClose,\n onSubmit,\n value,\n visible,\n}: AgeCheckSelectBirthdateProps) {\n if (!visible) return null\n\n const today = new Date()\n const selected = value || today\n\n const handleAndroidDateChange = (event: DateTimePickerEvent, selectedDate?: Date) => {\n if (event.type === 'set' && selectedDate) {\n onSubmit(selectedDate)\n }\n onRequestClose()\n }\n\n return (\n <DateTimePicker\n testID=\"age-check-date-picker-android\"\n mode=\"date\"\n display=\"spinner\"\n value={selected}\n maximumDate={today}\n onChange={handleAndroidDateChange}\n />\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n formSheet: {\n backgroundColor: colors.surfaceColor080,\n },\n formSheetContent: {\n flex: 1,\n },\n content: {\n flex: 1,\n backgroundColor: colors.surfaceColor080,\n padding: 16,\n justifyContent: 'flex-start',\n },\n card: {\n backgroundColor: colors.surfaceColor100,\n borderRadius: 8,\n padding: 16,\n },\n label: {\n marginBottom: 8,\n textTransform: 'uppercase',\n },\n pickerContainer: {\n backgroundColor: colors.surfaceColor100,\n borderRadius: 8,\n },\n })\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './age_check_required_screen';
2
+ export * from './age_check_underage_screen';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/age_check/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './age_check_required_screen';
2
+ export * from './age_check_underage_screen';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/screens/age_check/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA","sourcesContent":["export * from './age_check_required_screen'\nexport * from './age_check_underage_screen'\n"]}
@@ -0,0 +1,5 @@
1
+ export type AgeCheckContactInfo = {
2
+ contactEmail?: string;
3
+ };
4
+ export type AgeCheckParams = Record<string, AgeCheckContactInfo>;
5
+ //# sourceMappingURL=screen_props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen_props.d.ts","sourceRoot":"","sources":["../../../src/screens/age_check/screen_props.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=screen_props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen_props.js","sourceRoot":"","sources":["../../../src/screens/age_check/screen_props.ts"],"names":[],"mappings":"","sourcesContent":["export type AgeCheckContactInfo = { contactEmail?: string }\n\nexport type AgeCheckParams = Record<string, AgeCheckContactInfo>\n"]}
@@ -6,4 +6,5 @@ export * from './person';
6
6
  export * from './groups';
7
7
  export * from './app_grant';
8
8
  export * from './services';
9
+ export * from './organization';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
@@ -6,4 +6,5 @@ export * from './person';
6
6
  export * from './groups';
7
7
  export * from './app_grant';
8
8
  export * from './services';
9
+ export * from './organization';
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA","sourcesContent":["export * from './conversation'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA","sourcesContent":["export * from './conversation'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\nexport * from './organization'\n"]}
@@ -0,0 +1,6 @@
1
+ import { ResourceObject } from '../api_primitives';
2
+ export interface OrganizationResource extends ResourceObject {
3
+ type: 'Organization';
4
+ contactEmail?: string;
5
+ }
6
+ //# sourceMappingURL=organization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization.d.ts","sourceRoot":"","sources":["../../../src/types/resources/organization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D,IAAI,EAAE,cAAc,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=organization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization.js","sourceRoot":"","sources":["../../../src/types/resources/organization.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface OrganizationResource extends ResourceObject {\n type: 'Organization'\n contactEmail?: string\n}\n"]}
@@ -1,4 +1,10 @@
1
1
  import { ResourceObject } from '../api_primitives';
2
+ export declare const AgeQualificationStatus: {
3
+ readonly QUALIFIED: "qualified";
4
+ readonly DISQUALIFIED: "disqualified";
5
+ readonly UNKNOWN: "unknown";
6
+ };
7
+ export type AgeQualificationStatus = (typeof AgeQualificationStatus)[keyof typeof AgeQualificationStatus];
2
8
  export interface PersonResource extends ResourceObject {
3
9
  id: number;
4
10
  type: 'Person';
@@ -9,5 +15,6 @@ export interface CurrentPersonResource extends PersonResource {
9
15
  canChat: boolean;
10
16
  unreadCount: number;
11
17
  pcoChatEnabled: boolean;
18
+ ageQualificationStatus?: AgeQualificationStatus;
12
19
  }
13
20
  //# sourceMappingURL=person.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;CACxB"}
1
+ {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAA;AAEV,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAA;AAEtE,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;IACvB,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;CAChD"}
@@ -1,2 +1,6 @@
1
- export {};
1
+ export const AgeQualificationStatus = {
2
+ QUALIFIED: 'qualified',
3
+ DISQUALIFIED: 'disqualified',
4
+ UNKNOWN: 'unknown',
5
+ };
2
6
  //# sourceMappingURL=person.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface PersonResource extends ResourceObject {\n id: number\n type: 'Person'\n name: string\n avatar: string\n}\n\nexport interface CurrentPersonResource extends PersonResource {\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n}\n"]}
1
+ {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;CACV,CAAA","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport const AgeQualificationStatus = {\n QUALIFIED: 'qualified',\n DISQUALIFIED: 'disqualified',\n UNKNOWN: 'unknown',\n} as const\n\nexport type AgeQualificationStatus =\n (typeof AgeQualificationStatus)[keyof typeof AgeQualificationStatus]\n\nexport interface PersonResource extends ResourceObject {\n id: number\n type: 'Person'\n name: string\n avatar: string\n}\n\nexport interface CurrentPersonResource extends PersonResource {\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n ageQualificationStatus?: AgeQualificationStatus\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.16.0-rc.4",
3
+ "version": "3.16.0-rc.6",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "@planningcenter/datetime-fmt": ">=1.0.0",
24
24
  "@planningcenter/icons": "^15.24.0",
25
25
  "@planningcenter/jolt-client": ">=2.0.0",
26
+ "@react-native-community/datetimepicker": ">=7.6.2",
26
27
  "@react-navigation/elements": "*",
27
28
  "@react-navigation/native": ">=7.0.0",
28
29
  "@react-navigation/native-stack": ">=7.0.0",
@@ -55,5 +56,5 @@
55
56
  "react-native-url-polyfill": "^2.0.0",
56
57
  "typescript": "<5.6.0"
57
58
  },
58
- "gitHead": "9de20581feb4dbad2ab84082321718816506a330"
59
+ "gitHead": "20afe35a19110fdc1e1bcd1b15fb47670e93f98b"
59
60
  }
@@ -141,7 +141,7 @@ export function Message({
141
141
  onPress={() => setShowMessageMetaToggle(!showMessageMetaToggle)}
142
142
  onPressIn={handleMessagePressIn}
143
143
  onPressOut={handleMessagePressOut}
144
- android_ripple={{ color: colors.androidRippleNeutral }}
144
+ android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}
145
145
  accessibilityHint="Long press to view message actions like reacting and copying."
146
146
  >
147
147
  <Animated.View style={[styles.message, animatedBackgroundColor]}>
@@ -4,10 +4,12 @@ import { ColorSchemeName, useColorScheme } from 'react-native'
4
4
  import { DeepPartial } from '../types'
5
5
  import { ENV, OauthType, PartialToken, ResponseError, Session } from '../utils'
6
6
  import { ChatTheme, defaultTheme, DefaultTheme } from '../utils/theme'
7
+ import { AgeCheckContactInfo } from '../screens/age_check/screen_props'
7
8
 
8
9
  export interface ChatProviderProps {
9
10
  env?: ENV
10
11
  giphyApiKey?: string
12
+ onAgeDisqualification?: (params: AgeCheckContactInfo) => void
11
13
  onUnauthorizedResponse: (_response: ResponseError) => void
12
14
  token?: PartialToken
13
15
  tokenType?: OauthType
@@ -18,11 +20,13 @@ export interface ChatProviderProps {
18
20
  export interface ChatContextValue extends Omit<ChatProviderProps, 'theme'> {
19
21
  session: Session
20
22
  theme: ChatTheme
23
+ onAgeDisqualification: (params: AgeCheckContactInfo) => void
21
24
  }
22
25
 
23
26
  export const ChatContext = createContext<ChatContextValue>({
24
27
  env: undefined,
25
28
  giphyApiKey: undefined,
29
+ onAgeDisqualification: (_params: AgeCheckContactInfo) => {},
26
30
  onUnauthorizedResponse: () => {},
27
31
  session: new Session(),
28
32
  theme: defaultTheme('light'),
@@ -31,7 +35,15 @@ export const ChatContext = createContext<ChatContextValue>({
31
35
  })
32
36
 
33
37
  export function ChatProvider({ children, value }: { children: any; value: ChatProviderProps }) {
34
- const { env, token, onUnauthorizedResponse, giphyApiKey, tokenType, edgeToEdge = true } = value
38
+ const {
39
+ env,
40
+ token,
41
+ onAgeDisqualification = (_params: AgeCheckContactInfo) => {},
42
+ onUnauthorizedResponse,
43
+ giphyApiKey,
44
+ tokenType,
45
+ edgeToEdge = true,
46
+ } = value
35
47
  const theme = useCreateChatTheme(value.theme || {})
36
48
  const session = useMemo(
37
49
  () => new Session({ token, env, type: tokenType }),
@@ -42,6 +54,7 @@ export function ChatProvider({ children, value }: { children: any; value: ChatPr
42
54
  edgeToEdge,
43
55
  env,
44
56
  giphyApiKey,
57
+ onAgeDisqualification,
45
58
  onUnauthorizedResponse,
46
59
  session,
47
60
  theme,
@@ -14,4 +14,7 @@ export * from './use_api_client'
14
14
  export * from './use_message_reaction_toggle'
15
15
  export * from './use_interaction_ghost_color'
16
16
  export * from './use_at_font_scale_breakpoint'
17
+ export * from './use_qualified_by_age'
17
18
  export * from './use_scalable_number_of_lines'
19
+ export * from './use_submit_age_check'
20
+ export * from './use_organization'
@@ -7,7 +7,15 @@ export const currentPersonRequestArgs = {
7
7
  url: '/me',
8
8
  data: {
9
9
  fields: {
10
- Person: ['id', 'name', 'avatar', 'can_chat', 'unread_count', 'pco_chat_enabled'],
10
+ Person: [
11
+ 'id',
12
+ 'name',
13
+ 'avatar',
14
+ 'can_chat',
15
+ 'unread_count',
16
+ 'pco_chat_enabled',
17
+ 'age_qualification_status',
18
+ ],
11
19
  },
12
20
  },
13
21
  }
@@ -0,0 +1,17 @@
1
+ import { OrganizationResource } from '../types'
2
+ import { useSuspenseGet } from './use_suspense_api'
3
+ import { App } from './use_api_client'
4
+
5
+ export const organizationRequestArgs = {
6
+ url: '/',
7
+ data: {
8
+ fields: {
9
+ Organization: ['contact_email'],
10
+ },
11
+ },
12
+ app: 'chat' as App,
13
+ }
14
+
15
+ export function useOrganization() {
16
+ return useSuspenseGet<OrganizationResource>(organizationRequestArgs)
17
+ }
@@ -0,0 +1,17 @@
1
+ import { AgeQualificationStatus, CurrentPersonResource } from '../types'
2
+ import { useApiGet } from './use_api'
3
+ import { currentPersonRequestArgs } from './use_current_person'
4
+
5
+ export const useQualifiedByAge = (): boolean => {
6
+ const { data: person, isFetched } = useApiGet<CurrentPersonResource>(currentPersonRequestArgs)
7
+
8
+ if (!isFetched) {
9
+ return false
10
+ }
11
+
12
+ if (!person) {
13
+ return false
14
+ }
15
+
16
+ return person.ageQualificationStatus === AgeQualificationStatus.QUALIFIED
17
+ }
@@ -0,0 +1,48 @@
1
+ import { Alert } from 'react-native'
2
+ import { useMutation, useQueryClient } from '@tanstack/react-query'
3
+ import { useApiClient } from './use_api_client'
4
+ import { currentPersonQueryKey } from './use_current_person'
5
+ import { ApiResource } from '../types/api_primitives'
6
+ import { Haptic } from '../utils/native_adapters'
7
+
8
+ interface AgeCheckResource {
9
+ type: 'AgeCheck'
10
+ id: string
11
+ stated_date: string
12
+ status: 'passed' | 'failed'
13
+ }
14
+
15
+ export function useSubmitAgeCheck() {
16
+ const apiClient = useApiClient()
17
+ const queryClient = useQueryClient()
18
+
19
+ const { mutateAsync: submitAgeCheck, ...mutation } = useMutation({
20
+ mutationKey: ['submitAgeCheck'],
21
+ mutationFn: (date: Date) =>
22
+ apiClient.people.post<ApiResource<AgeCheckResource>>({
23
+ url: '/me/age_checks',
24
+ data: {
25
+ fields: { AgeCheck: 'stated_date,status' },
26
+ data: {
27
+ type: 'AgeCheck',
28
+ attributes: {
29
+ stated_date: date.toISOString(),
30
+ },
31
+ },
32
+ },
33
+ }),
34
+ onSuccess: (response: ApiResource<AgeCheckResource>) => {
35
+ queryClient.invalidateQueries({ queryKey: currentPersonQueryKey })
36
+ if (response.data.status === 'passed') {
37
+ Haptic.notificationSuccess()
38
+ Alert.alert('Profile updated', `Your birthdate has been updated.`)
39
+ }
40
+ },
41
+ onError: () => {
42
+ Haptic.notificationError()
43
+ Alert.alert('Oops', `We were unable to update your birthdate. Please try again.`)
44
+ },
45
+ })
46
+
47
+ return { submitAgeCheck, ...mutation }
48
+ }
package/src/index.tsx CHANGED
@@ -4,6 +4,7 @@ export * from './contexts/chat_context'
4
4
  export * from './navigation'
5
5
  export { ScreenLayout } from './navigation/screenLayout'
6
6
  export * from './screens'
7
+ export { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen' // TODO: add to barrel
7
8
  export * from './types'
8
9
  export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'
9
10
  export * from './utils/client'
@@ -0,0 +1,60 @@
1
+ import React, { PropsWithChildren, useEffect, useRef } from 'react'
2
+ import { currentPersonRequestArgs } from '../hooks/use_current_person'
3
+ import { AgeCheckRequiredScreen } from '../screens/age_check/age_check_required_screen'
4
+ import { DefaultLoading } from '../components/page/loading'
5
+ import { useApiGet, useOrganization } from '../hooks'
6
+ import { AgeQualificationStatus, CurrentPersonResource } from '../types'
7
+ import { useChatContext } from '../contexts/chat_context'
8
+ import { AgeCheckUnderageScreen } from '../screens/age_check/age_check_underage_screen'
9
+
10
+ export function ChatAccessGate({ children }: PropsWithChildren) {
11
+ const { data: person, isFetched } = useApiGet<CurrentPersonResource>(currentPersonRequestArgs)
12
+ const { data: organization } = useOrganization()
13
+
14
+ const ageQualificationStatus = person?.ageQualificationStatus
15
+ const contactEmail = organization?.contactEmail
16
+
17
+ useAgeDisqualification(ageQualificationStatus, contactEmail)
18
+
19
+ if (!isFetched) {
20
+ return <DefaultLoading />
21
+ }
22
+
23
+ if (!person) {
24
+ throw new Error('Current person not found')
25
+ }
26
+
27
+ if (ageQualificationStatus === AgeQualificationStatus.DISQUALIFIED) {
28
+ return <AgeCheckUnderageScreen contactEmail={contactEmail} />
29
+ }
30
+
31
+ if (ageQualificationStatus === AgeQualificationStatus.UNKNOWN) {
32
+ return <AgeCheckRequiredScreen />
33
+ }
34
+
35
+ return <>{children}</>
36
+ }
37
+
38
+ /**
39
+ * Helper hook that handles the age disqualification logic.
40
+ *
41
+ * If a host app provides an onAgeDisqualification callback, it will be called
42
+ * when a user is found to be disqualified by their age.
43
+ */
44
+ function useAgeDisqualification(
45
+ ageQualificationStatus: CurrentPersonResource['ageQualificationStatus'],
46
+ contactEmail: string | undefined
47
+ ) {
48
+ const { onAgeDisqualification } = useChatContext()
49
+ const hasCalledCallbackRef = useRef(false)
50
+
51
+ useEffect(() => {
52
+ if (
53
+ ageQualificationStatus === AgeQualificationStatus.DISQUALIFIED &&
54
+ !hasCalledCallbackRef.current
55
+ ) {
56
+ hasCalledCallbackRef.current = true
57
+ onAgeDisqualification({ contactEmail: contactEmail || '' })
58
+ }
59
+ }, [ageQualificationStatus, onAgeDisqualification, contactEmail])
60
+ }
@@ -45,9 +45,10 @@ import {
45
45
  } from '../screens/message_actions_screen'
46
46
  import { NotFound } from '../screens/not_found'
47
47
  import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
48
+ import { ScreenLayoutWithChatAccessGate } from './screenLayout'
48
49
  import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
49
50
  import { TeamConversationScreen } from '../screens/team_conversation_screen'
50
- import { ScreenLayout } from './screenLayout'
51
+ import { useQualifiedByAge } from '../hooks'
51
52
 
52
53
  const HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES = {
53
54
  marginLeft: Platform.select({ ios: -8, default: -3 }),
@@ -59,7 +60,7 @@ export const NewConversationStack = createNativeStackNavigator({
59
60
  screenOptions: {
60
61
  headerBackButtonDisplayMode: 'minimal',
61
62
  },
62
- screenLayout: ScreenLayout,
63
+ screenLayout: ScreenLayoutWithChatAccessGate,
63
64
  screens: {
64
65
  ConversationSelectRecipients: {
65
66
  screen: ConversationSelectRecipientsScreen,
@@ -122,7 +123,7 @@ export const ChatStack = createNativeStackNavigator({
122
123
  screenOptions: {
123
124
  headerBackButtonDisplayMode: 'minimal',
124
125
  },
125
- screenLayout: ScreenLayout,
126
+ screenLayout: ScreenLayoutWithChatAccessGate,
126
127
  screens: {
127
128
  Conversations: {
128
129
  screen: ConversationsScreen,
@@ -192,6 +193,7 @@ export const ChatStack = createNativeStackNavigator({
192
193
  },
193
194
  TeamConversation: {
194
195
  screen: TeamConversationScreen,
196
+ if: useQualifiedByAge,
195
197
  options: {
196
198
  title: 'Finding conversation...',
197
199
  animation: 'none',
@@ -210,6 +212,7 @@ export const ChatStack = createNativeStackNavigator({
210
212
  },
211
213
  New: {
212
214
  screen: NewConversationStack,
215
+ if: useQualifiedByAge,
213
216
  options: {
214
217
  headerShown: false,
215
218
  presentation: 'modal',
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import ErrorBoundary from '../components/page/error_boundary'
3
3
  import { Suspense } from 'react'
4
4
  import { DefaultLoading } from '../components/page/loading'
5
+ import { ChatAccessGate } from './chat_access_gate'
5
6
 
6
7
  export function ScreenLayout({ children }: { children: React.ReactElement }) {
7
8
  return (
@@ -10,3 +11,13 @@ export function ScreenLayout({ children }: { children: React.ReactElement }) {
10
11
  </ErrorBoundary>
11
12
  )
12
13
  }
14
+
15
+ export function ScreenLayoutWithChatAccessGate({ children }: { children: React.ReactElement }) {
16
+ return (
17
+ <ScreenLayout>
18
+ <ChatAccessGate>
19
+ <Suspense fallback={<DefaultLoading />}>{children}</Suspense>
20
+ </ChatAccessGate>
21
+ </ScreenLayout>
22
+ )
23
+ }