@planningcenter/chat-react-native 3.29.0 → 3.30.0-rc.0

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 (30) hide show
  1. package/build/hooks/groups/use_groups_conversation_create.d.ts +2 -1
  2. package/build/hooks/groups/use_groups_conversation_create.d.ts.map +1 -1
  3. package/build/hooks/groups/use_groups_conversation_create.js +2 -1
  4. package/build/hooks/groups/use_groups_conversation_create.js.map +1 -1
  5. package/build/hooks/use_features.d.ts +1 -0
  6. package/build/hooks/use_features.d.ts.map +1 -1
  7. package/build/hooks/use_features.js +1 -0
  8. package/build/hooks/use_features.js.map +1 -1
  9. package/build/hooks/use_my_gender.d.ts +7 -0
  10. package/build/hooks/use_my_gender.d.ts.map +1 -0
  11. package/build/hooks/use_my_gender.js +28 -0
  12. package/build/hooks/use_my_gender.js.map +1 -0
  13. package/build/screens/conversation_new/components/gender_filter_toggle.d.ts +10 -0
  14. package/build/screens/conversation_new/components/gender_filter_toggle.d.ts.map +1 -0
  15. package/build/screens/conversation_new/components/gender_filter_toggle.js +50 -0
  16. package/build/screens/conversation_new/components/gender_filter_toggle.js.map +1 -0
  17. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  18. package/build/screens/conversation_new/components/groups_form.js +27 -3
  19. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  20. package/build/utils/gender_display_label.d.ts +2 -0
  21. package/build/utils/gender_display_label.d.ts.map +1 -0
  22. package/build/utils/gender_display_label.js +11 -0
  23. package/build/utils/gender_display_label.js.map +1 -0
  24. package/package.json +2 -2
  25. package/src/hooks/groups/use_groups_conversation_create.ts +3 -1
  26. package/src/hooks/use_features.ts +1 -0
  27. package/src/hooks/use_my_gender.ts +42 -0
  28. package/src/screens/conversation_new/components/gender_filter_toggle.tsx +92 -0
  29. package/src/screens/conversation_new/components/groups_form.tsx +62 -3
  30. package/src/utils/gender_display_label.ts +10 -0
@@ -2,8 +2,9 @@ import { ApiResource, ConversationResource } from '../../types';
2
2
  interface Props {
3
3
  groupId: number;
4
4
  title?: string;
5
+ genderId?: string | null;
5
6
  onSuccess: (conversationId: number) => void;
6
7
  }
7
- export declare function useGroupsConversationCreate({ groupId, title, onSuccess }: Props): import("@tanstack/react-query").UseMutationResult<ApiResource<ConversationResource>, Error, void, unknown>;
8
+ export declare function useGroupsConversationCreate({ groupId, title, genderId, onSuccess }: Props): import("@tanstack/react-query").UseMutationResult<ApiResource<ConversationResource>, Error, void, unknown>;
8
9
  export {};
9
10
  //# sourceMappingURL=use_groups_conversation_create.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_groups_conversation_create.d.ts","sourceRoot":"","sources":["../../../src/hooks/groups/use_groups_conversation_create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAkB,MAAM,aAAa,CAAA;AAI/E,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C;AAED,wBAAgB,2BAA2B,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,8GAoC/E"}
1
+ {"version":3,"file":"use_groups_conversation_create.d.ts","sourceRoot":"","sources":["../../../src/hooks/groups/use_groups_conversation_create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAkB,MAAM,aAAa,CAAA;AAI/E,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C;AAED,wBAAgB,2BAA2B,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,8GAqCzF"}
@@ -1,7 +1,7 @@
1
1
  import { useMutation } from '@tanstack/react-query';
2
2
  import { useApiClient } from '../use_api_client';
3
3
  import { throwResponseError } from '../../utils/response_error';
4
- export function useGroupsConversationCreate({ groupId, title, onSuccess }) {
4
+ export function useGroupsConversationCreate({ groupId, title, genderId, onSuccess }) {
5
5
  const apiClient = useApiClient();
6
6
  return useMutation({
7
7
  throwOnError: true,
@@ -28,6 +28,7 @@ export function useGroupsConversationCreate({ groupId, title, onSuccess }) {
28
28
  type: 'Conversation',
29
29
  attributes: {
30
30
  payload,
31
+ ...(genderId ? { gender_id: genderId } : {}),
31
32
  },
32
33
  },
33
34
  },
@@ -1 +1 @@
1
- {"version":3,"file":"use_groups_conversation_create.js","sourceRoot":"","sources":["../../../src/hooks/groups/use_groups_conversation_create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAQ/D,MAAM,UAAU,2BAA2B,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAS;IAC9E,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,OAAO,WAAW,CAAC;QACjB,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,MAAM,CAAC,EAAE;YAClB,SAAS,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxC,CAAC;QACD,UAAU,EAAE,GAAG,EAAE,CACf,SAAS,CAAC,MAAM;aACb,IAAI,CAAuC;YAC1C,GAAG,EAAE,cAAc,OAAO,4BAA4B;YACtD,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,IAAI,EAAE,EAAE;oBACR,UAAU,EAAE;wBACV,KAAK;qBACN;iBACF;aACF;SACF,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;aAC3B,IAAI,CAAC,OAAO,CAAC,EAAE,CACd,SAAS,CAAC,IAAI,CAAC,IAAI,CAAoC;YACrD,GAAG,EAAE,mBAAmB;YACxB,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE;wBACV,OAAO;qBACR;iBACF;aACF;SACF,CAAC,CACH;aACA,KAAK,CAAC,kBAAkB,CAAC;KAC/B,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { useMutation } from '@tanstack/react-query'\nimport { ApiResource, ConversationResource, ResourceObject } from '../../types'\nimport { useApiClient } from '../use_api_client'\nimport { throwResponseError } from '../../utils/response_error'\n\ninterface Props {\n groupId: number\n title?: string\n onSuccess: (conversationId: number) => void\n}\n\nexport function useGroupsConversationCreate({ groupId, title, onSuccess }: Props) {\n const apiClient = useApiClient()\n return useMutation({\n throwOnError: true,\n onSuccess: result => {\n onSuccess && onSuccess(result.data.id)\n },\n mutationFn: () =>\n apiClient.groups\n .post<ApiResource<ChatConversationPayload>>({\n url: `/me/groups/${groupId}/chat_conversation_payload`,\n data: {\n data: {\n type: '',\n attributes: {\n title,\n },\n },\n },\n })\n .then(res => res.data.value)\n .then(payload =>\n apiClient.chat.post<ApiResource<ConversationResource>>({\n url: '/me/conversations',\n data: {\n data: {\n type: 'Conversation',\n attributes: {\n payload,\n },\n },\n },\n })\n )\n .catch(throwResponseError),\n })\n}\n\ninterface ChatConversationPayload extends ResourceObject {\n value: string\n}\n"]}
1
+ {"version":3,"file":"use_groups_conversation_create.js","sourceRoot":"","sources":["../../../src/hooks/groups/use_groups_conversation_create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAS/D,MAAM,UAAU,2BAA2B,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAS;IACxF,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,OAAO,WAAW,CAAC;QACjB,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,MAAM,CAAC,EAAE;YAClB,SAAS,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxC,CAAC;QACD,UAAU,EAAE,GAAG,EAAE,CACf,SAAS,CAAC,MAAM;aACb,IAAI,CAAuC;YAC1C,GAAG,EAAE,cAAc,OAAO,4BAA4B;YACtD,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,IAAI,EAAE,EAAE;oBACR,UAAU,EAAE;wBACV,KAAK;qBACN;iBACF;aACF;SACF,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;aAC3B,IAAI,CAAC,OAAO,CAAC,EAAE,CACd,SAAS,CAAC,IAAI,CAAC,IAAI,CAAoC;YACrD,GAAG,EAAE,mBAAmB;YACxB,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE;wBACV,OAAO;wBACP,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC7C;iBACF;aACF;SACF,CAAC,CACH;aACA,KAAK,CAAC,kBAAkB,CAAC;KAC/B,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { useMutation } from '@tanstack/react-query'\nimport { ApiResource, ConversationResource, ResourceObject } from '../../types'\nimport { useApiClient } from '../use_api_client'\nimport { throwResponseError } from '../../utils/response_error'\n\ninterface Props {\n groupId: number\n title?: string\n genderId?: string | null\n onSuccess: (conversationId: number) => void\n}\n\nexport function useGroupsConversationCreate({ groupId, title, genderId, onSuccess }: Props) {\n const apiClient = useApiClient()\n return useMutation({\n throwOnError: true,\n onSuccess: result => {\n onSuccess && onSuccess(result.data.id)\n },\n mutationFn: () =>\n apiClient.groups\n .post<ApiResource<ChatConversationPayload>>({\n url: `/me/groups/${groupId}/chat_conversation_payload`,\n data: {\n data: {\n type: '',\n attributes: {\n title,\n },\n },\n },\n })\n .then(res => res.data.value)\n .then(payload =>\n apiClient.chat.post<ApiResource<ConversationResource>>({\n url: '/me/conversations',\n data: {\n data: {\n type: 'Conversation',\n attributes: {\n payload,\n ...(genderId ? { gender_id: genderId } : {}),\n },\n },\n },\n })\n )\n .catch(throwResponseError),\n })\n}\n\ninterface ChatConversationPayload extends ResourceObject {\n value: string\n}\n"]}
@@ -6,5 +6,6 @@ export declare function useFeatures(): {
6
6
  export declare const availableFeatures: {
7
7
  message_reporting: string;
8
8
  granular_notifications_ui: string;
9
+ gender_specific_conversations: string;
9
10
  };
10
11
  //# sourceMappingURL=use_features.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_features.d.ts","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AAG1E,wBAAgB,WAAW;;kCAiBT,MAAM;EASvB;AAED,eAAO,MAAM,iBAAiB;;;CAG7B,CAAA"}
1
+ {"version":3,"file":"use_features.d.ts","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AAG1E,wBAAgB,WAAW;;kCAiBT,MAAM;EASvB;AAED,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAA"}
@@ -24,6 +24,7 @@ export function useFeatures() {
24
24
  export const availableFeatures = {
25
25
  message_reporting: 'ROLLOUT_MOBILE_message_reporting',
26
26
  granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',
27
+ gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',
27
28
  };
28
29
  const stableEmptyFeatures = {
29
30
  data: [],
@@ -1 +1 @@
1
- {"version":3,"file":"use_features.js","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI/C,MAAM,UAAU,WAAW;IACzB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAA;IAE5C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC;QAChC,QAAQ,EAAE,mBAAmB,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,SAAS,CAAC,IAAI;iBAClB,GAAG,CAAiC,WAAW,CAAC;iBAChD,KAAK,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAA;QACrC,CAAC;QACD,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;KACvC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;IAE1B,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,WAAmB,EAAE,EAAE,CACtB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,EAC3E,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO;QACL,QAAQ;QACR,cAAc;KACf,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,iBAAiB,EAAE,kCAAkC;IACrD,yBAAyB,EAAE,8CAA8C;CAC1E,CAAA;AAED,MAAM,mBAAmB,GAAmC;IAC1D,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,CAAC;QACR,UAAU,EAAE,CAAC;KACd;CACF,CAAA","sourcesContent":["import { useSuspenseQuery } from '@tanstack/react-query'\nimport { useCallback } from 'react'\nimport { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'\nimport { useApiClient } from './use_api_client'\nimport type { FeatureResource } from '../types/resources/feature_resource'\nimport { ApiCollection } from '../types'\n\nexport function useFeatures() {\n const apiClient = useApiClient()\n const requestArgs = getFeaturesRequestArgs()\n\n const { data } = useSuspenseQuery({\n queryKey: getFeaturesQueryKey(),\n queryFn: () => {\n return apiClient.chat\n .get<ApiCollection<FeatureResource>>(requestArgs)\n .catch(() => stableEmptyFeatures)\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n\n const features = data.data\n\n const featureEnabled = useCallback(\n (featureName: string) =>\n features.some(feature => feature.name === featureName && feature.enabled),\n [features]\n )\n\n return {\n features,\n featureEnabled,\n }\n}\n\nexport const availableFeatures = {\n message_reporting: 'ROLLOUT_MOBILE_message_reporting',\n granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',\n}\n\nconst stableEmptyFeatures: ApiCollection<FeatureResource> = {\n data: [],\n links: {},\n meta: {\n count: 0,\n totalCount: 0,\n },\n}\n"]}
1
+ {"version":3,"file":"use_features.js","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI/C,MAAM,UAAU,WAAW;IACzB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAA;IAE5C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC;QAChC,QAAQ,EAAE,mBAAmB,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,SAAS,CAAC,IAAI;iBAClB,GAAG,CAAiC,WAAW,CAAC;iBAChD,KAAK,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAA;QACrC,CAAC;QACD,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;KACvC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;IAE1B,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,WAAmB,EAAE,EAAE,CACtB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,EAC3E,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO;QACL,QAAQ;QACR,cAAc;KACf,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,iBAAiB,EAAE,kCAAkC;IACrD,yBAAyB,EAAE,8CAA8C;IACzE,6BAA6B,EAAE,uCAAuC;CACvE,CAAA;AAED,MAAM,mBAAmB,GAAmC;IAC1D,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,CAAC;QACR,UAAU,EAAE,CAAC;KACd;CACF,CAAA","sourcesContent":["import { useSuspenseQuery } from '@tanstack/react-query'\nimport { useCallback } from 'react'\nimport { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'\nimport { useApiClient } from './use_api_client'\nimport type { FeatureResource } from '../types/resources/feature_resource'\nimport { ApiCollection } from '../types'\n\nexport function useFeatures() {\n const apiClient = useApiClient()\n const requestArgs = getFeaturesRequestArgs()\n\n const { data } = useSuspenseQuery({\n queryKey: getFeaturesQueryKey(),\n queryFn: () => {\n return apiClient.chat\n .get<ApiCollection<FeatureResource>>(requestArgs)\n .catch(() => stableEmptyFeatures)\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n\n const features = data.data\n\n const featureEnabled = useCallback(\n (featureName: string) =>\n features.some(feature => feature.name === featureName && feature.enabled),\n [features]\n )\n\n return {\n features,\n featureEnabled,\n }\n}\n\nexport const availableFeatures = {\n message_reporting: 'ROLLOUT_MOBILE_message_reporting',\n granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',\n gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',\n}\n\nconst stableEmptyFeatures: ApiCollection<FeatureResource> = {\n data: [],\n links: {},\n meta: {\n count: 0,\n totalCount: 0,\n },\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export declare function useMyGender(): {
2
+ isFeatureEnabled: boolean;
3
+ genderValue: string | null;
4
+ genderId: string | null;
5
+ isFetching: boolean;
6
+ };
7
+ //# sourceMappingURL=use_my_gender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_my_gender.d.ts","sourceRoot":"","sources":["../../src/hooks/use_my_gender.ts"],"names":[],"mappings":"AAcA,wBAAgB,WAAW;;;;;EA2B1B"}
@@ -0,0 +1,28 @@
1
+ import { useApiGet } from './use_api';
2
+ import { availableFeatures, useFeatures } from './use_features';
3
+ export function useMyGender() {
4
+ const { featureEnabled } = useFeatures();
5
+ const isFeatureEnabled = featureEnabled(availableFeatures.gender_specific_conversations);
6
+ const { data, isFetching } = useApiGet({
7
+ url: '/me',
8
+ enabled: isFeatureEnabled,
9
+ data: {
10
+ include: ['gender'],
11
+ fields: {
12
+ Person: ['gender'],
13
+ Gender: ['value'],
14
+ },
15
+ },
16
+ app: 'people',
17
+ });
18
+ const gender = data?.gender;
19
+ const genderValue = gender?.value ?? null;
20
+ const genderId = gender?.id ? String(gender.id) : null;
21
+ return {
22
+ isFeatureEnabled,
23
+ genderValue,
24
+ genderId,
25
+ isFetching,
26
+ };
27
+ }
28
+ //# sourceMappingURL=use_my_gender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_my_gender.js","sourceRoot":"","sources":["../../src/hooks/use_my_gender.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAY/D,MAAM,UAAU,WAAW;IACzB,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,EAAE,CAAA;IACxC,MAAM,gBAAgB,GAAG,cAAc,CAAC,iBAAiB,CAAC,6BAA6B,CAAC,CAAA;IAExF,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,SAAS,CAAmB;QACvD,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE;YACJ,OAAO,EAAE,CAAC,QAAQ,CAAC;YACnB,MAAM,EAAE;gBACN,MAAM,EAAE,CAAC,QAAQ,CAAC;gBAClB,MAAM,EAAE,CAAC,OAAO,CAAC;aAClB;SACF;QACD,GAAG,EAAE,QAAQ;KACd,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,CAAA;IAC3B,MAAM,WAAW,GAAG,MAAM,EAAE,KAAK,IAAI,IAAI,CAAA;IACzC,MAAM,QAAQ,GAAG,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEtD,OAAO;QACL,gBAAgB;QAChB,WAAW;QACX,QAAQ;QACR,UAAU;KACX,CAAA;AACH,CAAC","sourcesContent":["import { ResourceObject } from '../types/api_primitives'\nimport { useApiGet } from './use_api'\nimport { availableFeatures, useFeatures } from './use_features'\n\ninterface GenderResource extends ResourceObject {\n type: 'Gender'\n value: string\n}\n\ninterface PersonWithGender extends ResourceObject {\n type: 'Person'\n gender: GenderResource | undefined\n}\n\nexport function useMyGender() {\n const { featureEnabled } = useFeatures()\n const isFeatureEnabled = featureEnabled(availableFeatures.gender_specific_conversations)\n\n const { data, isFetching } = useApiGet<PersonWithGender>({\n url: '/me',\n enabled: isFeatureEnabled,\n data: {\n include: ['gender'],\n fields: {\n Person: ['gender'],\n Gender: ['value'],\n },\n },\n app: 'people',\n })\n\n const gender = data?.gender\n const genderValue = gender?.value ?? null\n const genderId = gender?.id ? String(gender.id) : null\n\n return {\n isFeatureEnabled,\n genderValue,\n genderId,\n isFetching,\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface GenderFilterToggleProps {
3
+ genderValue: string | null;
4
+ isFetching: boolean;
5
+ enabled: boolean;
6
+ onToggle: (enabled: boolean) => void;
7
+ }
8
+ export declare function GenderFilterToggle({ genderValue, isFetching, enabled, onToggle, }: GenderFilterToggleProps): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=gender_filter_toggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gender_filter_toggle.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/gender_filter_toggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAmDzB,UAAU,uBAAuB;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACrC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,WAAW,EACX,UAAU,EACV,OAAO,EACP,QAAQ,GACT,EAAE,uBAAuB,qBAczB"}
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { ActivityIndicator, StyleSheet, View } from 'react-native';
3
+ import { Heading, Switch, Text } from '../../../components';
4
+ import { useTheme } from '../../../hooks';
5
+ import { genderDisplayLabel } from '../../../utils/gender_display_label';
6
+ function FilterableGenderContent({ genderValue, enabled, onToggle }) {
7
+ const { colors } = useTheme();
8
+ const styles = useStyles();
9
+ const displayLabel = genderDisplayLabel(genderValue);
10
+ return (<>
11
+ <View style={styles.toggleRow}>
12
+ <Text>{displayLabel}</Text>
13
+ <Switch value={enabled} onValueChange={onToggle} accessibilityLabel={`Filter by ${displayLabel}`}/>
14
+ </View>
15
+ <Text style={{ color: colors.textColorDefaultSecondary }}>
16
+ Filter limited to your profile's set gender
17
+ </Text>
18
+ </>);
19
+ }
20
+ function NoGenderContent({ isFetching }) {
21
+ const { colors } = useTheme();
22
+ return (<>
23
+ <Text>Gender</Text>
24
+ {isFetching ? (<ActivityIndicator size="small"/>) : (<Text style={{ color: colors.textColorDefaultSecondary }}>
25
+ Set a gender in your Church Center profile to enable gender filtering.
26
+ </Text>)}
27
+ </>);
28
+ }
29
+ export function GenderFilterToggle({ genderValue, isFetching, enabled, onToggle, }) {
30
+ const styles = useStyles();
31
+ const hasFilterableGender = genderValue !== null && genderValue !== 'Prefer not to say';
32
+ return (<View style={styles.container}>
33
+ <Heading variant="h3">Filter by</Heading>
34
+ {hasFilterableGender ? (<FilterableGenderContent genderValue={genderValue} enabled={enabled} onToggle={onToggle}/>) : (<NoGenderContent isFetching={isFetching}/>)}
35
+ </View>);
36
+ }
37
+ const useStyles = () => {
38
+ return StyleSheet.create({
39
+ container: {
40
+ padding: 16,
41
+ gap: 8,
42
+ },
43
+ toggleRow: {
44
+ flexDirection: 'row',
45
+ justifyContent: 'space-between',
46
+ alignItems: 'center',
47
+ },
48
+ });
49
+ };
50
+ //# sourceMappingURL=gender_filter_toggle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gender_filter_toggle.js","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/gender_filter_toggle.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { ActivityIndicator, StyleSheet, View } from 'react-native'\nimport { Heading, Switch, Text } from '../../../components'\nimport { useTheme } from '../../../hooks'\nimport { genderDisplayLabel } from '../../../utils/gender_display_label'\n\ninterface FilterableGenderContentProps {\n genderValue: string\n enabled: boolean\n onToggle: (enabled: boolean) => void\n}\n\nfunction FilterableGenderContent({ genderValue, enabled, onToggle }: FilterableGenderContentProps) {\n const { colors } = useTheme()\n const styles = useStyles()\n const displayLabel = genderDisplayLabel(genderValue)\n\n return (\n <>\n <View style={styles.toggleRow}>\n <Text>{displayLabel}</Text>\n <Switch\n value={enabled}\n onValueChange={onToggle}\n accessibilityLabel={`Filter by ${displayLabel}`}\n />\n </View>\n <Text style={{ color: colors.textColorDefaultSecondary }}>\n Filter limited to your profile's set gender\n </Text>\n </>\n )\n}\n\nfunction NoGenderContent({ isFetching }: { isFetching: boolean }) {\n const { colors } = useTheme()\n\n return (\n <>\n <Text>Gender</Text>\n {isFetching ? (\n <ActivityIndicator size=\"small\" />\n ) : (\n <Text style={{ color: colors.textColorDefaultSecondary }}>\n Set a gender in your Church Center profile to enable gender filtering.\n </Text>\n )}\n </>\n )\n}\n\ninterface GenderFilterToggleProps {\n genderValue: string | null\n isFetching: boolean\n enabled: boolean\n onToggle: (enabled: boolean) => void\n}\n\nexport function GenderFilterToggle({\n genderValue,\n isFetching,\n enabled,\n onToggle,\n}: GenderFilterToggleProps) {\n const styles = useStyles()\n const hasFilterableGender = genderValue !== null && genderValue !== 'Prefer not to say'\n\n return (\n <View style={styles.container}>\n <Heading variant=\"h3\">Filter by</Heading>\n {hasFilterableGender ? (\n <FilterableGenderContent genderValue={genderValue} enabled={enabled} onToggle={onToggle} />\n ) : (\n <NoGenderContent isFetching={isFetching} />\n )}\n </View>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n container: {\n padding: 16,\n gap: 8,\n },\n toggleRow: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"groups_form.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAYrE,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAA;AAKjE,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,UAAU,qCAAsC,eAAe,sBA0D3E,CAAA"}
1
+ {"version":3,"file":"groups_form.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAYrE,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAA;AAQjE,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,UAAU,qCAAsC,eAAe,sBAwF3E,CAAA"}
@@ -8,11 +8,16 @@ import { useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks';
8
8
  import { useGroupMembersForNewConversation, } from '../../../hooks/groups/use_group_members_for_new_conversation';
9
9
  import { useGroupsConversationCreate } from '../../../hooks/groups/use_groups_conversation_create';
10
10
  import { pluralize } from '../../../utils';
11
+ import { genderDisplayLabel } from '../../../utils/gender_display_label';
11
12
  import { Divider, FormList } from './form_list';
13
+ import { GenderFilterToggle } from './gender_filter_toggle';
12
14
  import { Haptic } from '../../../utils/native_adapters';
15
+ import { useMyGender } from '../../../hooks/use_my_gender';
13
16
  export const GroupsForm = ({ groupId, chat_group_graph_id }) => {
14
17
  const navigation = useNavigation();
15
- const [title, setTitle] = useState();
18
+ const [title, setTitle] = useState('');
19
+ const [genderFilterEnabled, setGenderFilterEnabled] = useState(false);
20
+ const { isFeatureEnabled: genderFilterAvailable, genderId, genderValue, isFetching: genderFetching, } = useMyGender();
16
21
  const { data: group } = useSuspenseGet({
17
22
  url: `/me/groups/${groupId}`,
18
23
  data: {
@@ -23,6 +28,20 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }) => {
23
28
  app: 'groups',
24
29
  });
25
30
  const groupMemberships = useGroupMembersForNewConversation({ id: groupId });
31
+ const activeGenderId = genderFilterEnabled ? genderId : null;
32
+ const handleGenderToggle = (enabled) => {
33
+ const displayLabel = genderValue ? genderDisplayLabel(genderValue) : '';
34
+ const defaultTitle = `${group.name} (${displayLabel})`;
35
+ const shouldAutoPopulateTitle = enabled && genderValue && title === '';
36
+ const shouldClearAutoPopulatedTitle = !enabled && title === defaultTitle;
37
+ setGenderFilterEnabled(enabled);
38
+ if (shouldAutoPopulateTitle) {
39
+ setTitle(defaultTitle);
40
+ }
41
+ else if (shouldClearAutoPopulatedTitle) {
42
+ setTitle('');
43
+ }
44
+ };
26
45
  const redirectToConversation = useCallback((conversationId) => {
27
46
  // navigate to the conversation screen
28
47
  navigation.dispatch(StackActions.popTo('Conversation', {
@@ -34,14 +53,15 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }) => {
34
53
  const { mutate: handleSave, isPending } = useGroupsConversationCreate({
35
54
  groupId,
36
55
  title,
56
+ genderId: activeGenderId,
37
57
  onSuccess: redirectToConversation,
38
58
  });
39
59
  return (<KeyboardView>
40
- <FormList memberData={groupMemberships.adultMembers} loadingMore={groupMemberships.isFetchingNextPage} onEndReached={groupMemberships.fetchNextPage} FormContent={<FormContent group={group} title={title} setTitle={setTitle} groupMemberships={groupMemberships}/>}/>
60
+ <FormList memberData={groupMemberships.adultMembers} loadingMore={groupMemberships.isFetchingNextPage} onEndReached={groupMemberships.fetchNextPage} FormContent={<FormContent group={group} title={title} setTitle={setTitle} genderFilterAvailable={genderFilterAvailable} genderFilterEnabled={genderFilterEnabled} genderValue={genderValue} genderFetching={genderFetching} onGenderToggle={handleGenderToggle} groupMemberships={groupMemberships}/>}/>
41
61
  <ActionButton disabled={!title || isPending} title="Start Conversation" onPress={() => handleSave()} infoText="Conversation will be automatically updated if any members are added or removed from this group."/>
42
62
  </KeyboardView>);
43
63
  };
44
- function FormContent({ group, title, setTitle, groupMemberships }) {
64
+ function FormContent({ group, title, setTitle, genderFilterAvailable, genderFilterEnabled, genderValue, genderFetching, onGenderToggle, groupMemberships, }) {
45
65
  const styles = useStyles();
46
66
  const inputRef = useRef(null);
47
67
  const currentPerson = useCurrentPerson();
@@ -66,6 +86,10 @@ function FormContent({ group, title, setTitle, groupMemberships }) {
66
86
  <TextInput placeholder="Topic of conversation (required)" value={title} onChangeText={setTitle} style={styles.titleInput} autoFocus={true} ref={inputRef}/>
67
87
  </Pressable>
68
88
  <Divider />
89
+ {genderFilterAvailable && (<>
90
+ <GenderFilterToggle genderValue={genderValue} isFetching={genderFetching} enabled={genderFilterEnabled} onToggle={onGenderToggle}/>
91
+ <Divider />
92
+ </>)}
69
93
  <View style={styles.memberSection}>
70
94
  <Heading variant="h3">{memberHeaderLabel}</Heading>
71
95
  {hasChildren && (<ChildNotice childMembers={childMembers} showMembers={isLeader} style={styles.banner}/>)}
@@ -1 +1 @@
1
- {"version":3,"file":"groups_form.js","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StackActions, useNavigation } from '@react-navigation/native'\nimport React, { useCallback, useMemo, useRef, useState } from 'react'\nimport { Platform, Pressable, StyleSheet, TextInput, View } from 'react-native'\nimport { Banner, ChildNotice, Heading, Text } from '../../../components'\nimport { ActionButton } from '../../../components/display/action_button'\nimport { KeyboardView } from '../../../components/display/keyboard_view'\nimport { useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'\nimport {\n GroupMembersForNewConversationResult,\n useGroupMembersForNewConversation,\n} from '../../../hooks/groups/use_group_members_for_new_conversation'\nimport { useGroupsConversationCreate } from '../../../hooks/groups/use_groups_conversation_create'\nimport { GroupsGroupResource } from '../../../types'\nimport { GraphId } from '../../../types/resources/group_resource'\nimport { pluralize } from '../../../utils'\nimport { Divider, FormList } from './form_list'\nimport { Haptic } from '../../../utils/native_adapters'\n\ntype GroupsFormProps = {\n groupId: number\n chat_group_graph_id?: GraphId\n}\n\nexport const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) => {\n const navigation = useNavigation()\n const [title, setTitle] = useState<string>()\n const { data: group } = useSuspenseGet<GroupsGroupResource>({\n url: `/me/groups/${groupId}`,\n data: {\n fields: {\n Group: [],\n },\n },\n app: 'groups',\n })\n\n const groupMemberships = useGroupMembersForNewConversation({ id: groupId })\n\n const redirectToConversation = useCallback(\n (conversationId: number) => {\n // navigate to the conversation screen\n navigation.dispatch(\n StackActions.popTo('Conversation', {\n conversation_id: conversationId,\n chat_group_graph_id,\n })\n )\n Haptic.notificationSuccess()\n },\n [chat_group_graph_id, navigation]\n )\n\n const { mutate: handleSave, isPending } = useGroupsConversationCreate({\n groupId,\n title,\n onSuccess: redirectToConversation,\n })\n\n return (\n <KeyboardView>\n <FormList\n memberData={groupMemberships.adultMembers}\n loadingMore={groupMemberships.isFetchingNextPage}\n onEndReached={groupMemberships.fetchNextPage}\n FormContent={\n <FormContent\n group={group}\n title={title}\n setTitle={setTitle}\n groupMemberships={groupMemberships}\n />\n }\n />\n <ActionButton\n disabled={!title || isPending}\n title=\"Start Conversation\"\n onPress={() => handleSave()}\n infoText=\"Conversation will be automatically updated if any members are added or removed from this group.\"\n />\n </KeyboardView>\n )\n}\n\ninterface FormContentProps {\n group: GroupsGroupResource\n title?: string\n setTitle: (title: string) => void\n groupMemberships: GroupMembersForNewConversationResult\n}\n\nfunction FormContent({ group, title, setTitle, groupMemberships }: FormContentProps) {\n const styles = useStyles()\n const inputRef = useRef<TextInput>(null)\n const currentPerson = useCurrentPerson()\n const { name, membershipsCount } = group\n\n const myGroupsMembership = useMemo(\n () => groupMemberships.data.find(m => m.id === currentPerson.id),\n [groupMemberships.data, currentPerson.id]\n )\n const isLeader = myGroupsMembership?.role === 'leader'\n\n const childMembers = groupMemberships.childMembers\n const hasChildren = childMembers.length > 0\n const memberHeaderLabel = `${pluralize(membershipsCount, 'member')} selected`\n\n const showMemberError = groupMemberships.isError\n\n const handleTitleSectionPress = useCallback(() => {\n inputRef.current?.focus()\n }, [])\n\n return (\n <View style={styles.formContent}>\n <View style={styles.toSection}>\n <Heading variant=\"h3\">To:</Heading>\n <Text style={styles.groupName}>{name}</Text>\n </View>\n <Divider />\n <Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>\n <Heading variant=\"h3\">Title</Heading>\n <TextInput\n placeholder=\"Topic of conversation (required)\"\n value={title}\n onChangeText={setTitle}\n style={styles.titleInput}\n autoFocus={true}\n ref={inputRef}\n />\n </Pressable>\n <Divider />\n <View style={styles.memberSection}>\n <Heading variant=\"h3\">{memberHeaderLabel}</Heading>\n {hasChildren && (\n <ChildNotice childMembers={childMembers} showMembers={isLeader} style={styles.banner} />\n )}\n {showMemberError && (\n <Banner\n appearance=\"error\"\n description=\"There was an issue loading group members, please refresh and try again.\"\n style={styles.banner}\n />\n )}\n </View>\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const sectionPadding = 16\n const inputPadding = 8\n\n return StyleSheet.create({\n formContent: {\n paddingBottom: sectionPadding,\n flex: 1,\n },\n toSection: {\n padding: sectionPadding,\n flexDirection: 'row',\n gap: 8,\n },\n groupName: {\n fontSize: 18,\n flex: 1,\n },\n titleSection: {\n padding: sectionPadding,\n paddingBottom: Platform.select({\n ios: sectionPadding,\n android: sectionPadding - inputPadding,\n }),\n gap: Platform.select({\n ios: 8,\n android: 0,\n }),\n },\n titleInput: {\n fontSize: 18,\n color: colors.textColorDefaultPrimary,\n },\n memberSection: {\n padding: sectionPadding,\n paddingBottom: 0,\n },\n banner: {\n marginTop: 16,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"groups_form.js","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StackActions, useNavigation } from '@react-navigation/native'\nimport React, { useCallback, useMemo, useRef, useState } from 'react'\nimport { Platform, Pressable, StyleSheet, TextInput, View } from 'react-native'\nimport { Banner, ChildNotice, Heading, Text } from '../../../components'\nimport { ActionButton } from '../../../components/display/action_button'\nimport { KeyboardView } from '../../../components/display/keyboard_view'\nimport { useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'\nimport {\n GroupMembersForNewConversationResult,\n useGroupMembersForNewConversation,\n} from '../../../hooks/groups/use_group_members_for_new_conversation'\nimport { useGroupsConversationCreate } from '../../../hooks/groups/use_groups_conversation_create'\nimport { GroupsGroupResource } from '../../../types'\nimport { GraphId } from '../../../types/resources/group_resource'\nimport { pluralize } from '../../../utils'\nimport { genderDisplayLabel } from '../../../utils/gender_display_label'\nimport { Divider, FormList } from './form_list'\nimport { GenderFilterToggle } from './gender_filter_toggle'\nimport { Haptic } from '../../../utils/native_adapters'\nimport { useMyGender } from '../../../hooks/use_my_gender'\n\ntype GroupsFormProps = {\n groupId: number\n chat_group_graph_id?: GraphId\n}\n\nexport const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) => {\n const navigation = useNavigation()\n const [title, setTitle] = useState('')\n const [genderFilterEnabled, setGenderFilterEnabled] = useState(false)\n const {\n isFeatureEnabled: genderFilterAvailable,\n genderId,\n genderValue,\n isFetching: genderFetching,\n } = useMyGender()\n const { data: group } = useSuspenseGet<GroupsGroupResource>({\n url: `/me/groups/${groupId}`,\n data: {\n fields: {\n Group: [],\n },\n },\n app: 'groups',\n })\n\n const groupMemberships = useGroupMembersForNewConversation({ id: groupId })\n\n const activeGenderId = genderFilterEnabled ? genderId : null\n\n const handleGenderToggle = (enabled: boolean) => {\n const displayLabel = genderValue ? genderDisplayLabel(genderValue) : ''\n const defaultTitle = `${group.name} (${displayLabel})`\n const shouldAutoPopulateTitle = enabled && genderValue && title === ''\n const shouldClearAutoPopulatedTitle = !enabled && title === defaultTitle\n\n setGenderFilterEnabled(enabled)\n\n if (shouldAutoPopulateTitle) {\n setTitle(defaultTitle)\n } else if (shouldClearAutoPopulatedTitle) {\n setTitle('')\n }\n }\n\n const redirectToConversation = useCallback(\n (conversationId: number) => {\n // navigate to the conversation screen\n navigation.dispatch(\n StackActions.popTo('Conversation', {\n conversation_id: conversationId,\n chat_group_graph_id,\n })\n )\n Haptic.notificationSuccess()\n },\n [chat_group_graph_id, navigation]\n )\n\n const { mutate: handleSave, isPending } = useGroupsConversationCreate({\n groupId,\n title,\n genderId: activeGenderId,\n onSuccess: redirectToConversation,\n })\n\n return (\n <KeyboardView>\n <FormList\n memberData={groupMemberships.adultMembers}\n loadingMore={groupMemberships.isFetchingNextPage}\n onEndReached={groupMemberships.fetchNextPage}\n FormContent={\n <FormContent\n group={group}\n title={title}\n setTitle={setTitle}\n genderFilterAvailable={genderFilterAvailable}\n genderFilterEnabled={genderFilterEnabled}\n genderValue={genderValue}\n genderFetching={genderFetching}\n onGenderToggle={handleGenderToggle}\n groupMemberships={groupMemberships}\n />\n }\n />\n <ActionButton\n disabled={!title || isPending}\n title=\"Start Conversation\"\n onPress={() => handleSave()}\n infoText=\"Conversation will be automatically updated if any members are added or removed from this group.\"\n />\n </KeyboardView>\n )\n}\n\ninterface FormContentProps {\n group: GroupsGroupResource\n title: string\n setTitle: (title: string) => void\n genderFilterAvailable: boolean\n genderFilterEnabled: boolean\n genderValue: string | null\n genderFetching: boolean\n onGenderToggle: (enabled: boolean) => void\n groupMemberships: GroupMembersForNewConversationResult\n}\n\nfunction FormContent({\n group,\n title,\n setTitle,\n genderFilterAvailable,\n genderFilterEnabled,\n genderValue,\n genderFetching,\n onGenderToggle,\n groupMemberships,\n}: FormContentProps) {\n const styles = useStyles()\n const inputRef = useRef<TextInput>(null)\n const currentPerson = useCurrentPerson()\n const { name, membershipsCount } = group\n\n const myGroupsMembership = useMemo(\n () => groupMemberships.data.find(m => m.id === currentPerson.id),\n [groupMemberships.data, currentPerson.id]\n )\n const isLeader = myGroupsMembership?.role === 'leader'\n\n const childMembers = groupMemberships.childMembers\n const hasChildren = childMembers.length > 0\n const memberHeaderLabel = `${pluralize(membershipsCount, 'member')} selected`\n\n const showMemberError = groupMemberships.isError\n\n const handleTitleSectionPress = useCallback(() => {\n inputRef.current?.focus()\n }, [])\n\n return (\n <View style={styles.formContent}>\n <View style={styles.toSection}>\n <Heading variant=\"h3\">To:</Heading>\n <Text style={styles.groupName}>{name}</Text>\n </View>\n <Divider />\n <Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>\n <Heading variant=\"h3\">Title</Heading>\n <TextInput\n placeholder=\"Topic of conversation (required)\"\n value={title}\n onChangeText={setTitle}\n style={styles.titleInput}\n autoFocus={true}\n ref={inputRef}\n />\n </Pressable>\n <Divider />\n {genderFilterAvailable && (\n <>\n <GenderFilterToggle\n genderValue={genderValue}\n isFetching={genderFetching}\n enabled={genderFilterEnabled}\n onToggle={onGenderToggle}\n />\n <Divider />\n </>\n )}\n <View style={styles.memberSection}>\n <Heading variant=\"h3\">{memberHeaderLabel}</Heading>\n {hasChildren && (\n <ChildNotice childMembers={childMembers} showMembers={isLeader} style={styles.banner} />\n )}\n {showMemberError && (\n <Banner\n appearance=\"error\"\n description=\"There was an issue loading group members, please refresh and try again.\"\n style={styles.banner}\n />\n )}\n </View>\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const sectionPadding = 16\n const inputPadding = 8\n\n return StyleSheet.create({\n formContent: {\n paddingBottom: sectionPadding,\n flex: 1,\n },\n toSection: {\n padding: sectionPadding,\n flexDirection: 'row',\n gap: 8,\n },\n groupName: {\n fontSize: 18,\n flex: 1,\n },\n titleSection: {\n padding: sectionPadding,\n paddingBottom: Platform.select({\n ios: sectionPadding,\n android: sectionPadding - inputPadding,\n }),\n gap: Platform.select({\n ios: 8,\n android: 0,\n }),\n },\n titleInput: {\n fontSize: 18,\n color: colors.textColorDefaultPrimary,\n },\n memberSection: {\n padding: sectionPadding,\n paddingBottom: 0,\n },\n banner: {\n marginTop: 16,\n },\n })\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function genderDisplayLabel(genderOption: string): string;
2
+ //# sourceMappingURL=gender_display_label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gender_display_label.d.ts","sourceRoot":"","sources":["../../src/utils/gender_display_label.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS/D"}
@@ -0,0 +1,11 @@
1
+ export function genderDisplayLabel(genderOption) {
2
+ switch (genderOption) {
3
+ case 'Male':
4
+ return 'Men';
5
+ case 'Female':
6
+ return 'Women';
7
+ default:
8
+ return genderOption;
9
+ }
10
+ }
11
+ //# sourceMappingURL=gender_display_label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gender_display_label.js","sourceRoot":"","sources":["../../src/utils/gender_display_label.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,KAAK,CAAA;QACd,KAAK,QAAQ;YACX,OAAO,OAAO,CAAA;QAChB;YACE,OAAO,YAAY,CAAA;IACvB,CAAC;AACH,CAAC","sourcesContent":["export function genderDisplayLabel(genderOption: string): string {\n switch (genderOption) {\n case 'Male':\n return 'Men'\n case 'Female':\n return 'Women'\n default:\n return genderOption\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.29.0",
3
+ "version": "3.30.0-rc.0",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -58,5 +58,5 @@
58
58
  "react-native-url-polyfill": "^2.0.0",
59
59
  "typescript": "<5.6.0"
60
60
  },
61
- "gitHead": "2e11a15fcfbc1cee00c67c5cb3438c19ab3f90e1"
61
+ "gitHead": "3aada23dbbc180073007ecad60a146f46f57b744"
62
62
  }
@@ -6,10 +6,11 @@ import { throwResponseError } from '../../utils/response_error'
6
6
  interface Props {
7
7
  groupId: number
8
8
  title?: string
9
+ genderId?: string | null
9
10
  onSuccess: (conversationId: number) => void
10
11
  }
11
12
 
12
- export function useGroupsConversationCreate({ groupId, title, onSuccess }: Props) {
13
+ export function useGroupsConversationCreate({ groupId, title, genderId, onSuccess }: Props) {
13
14
  const apiClient = useApiClient()
14
15
  return useMutation({
15
16
  throwOnError: true,
@@ -38,6 +39,7 @@ export function useGroupsConversationCreate({ groupId, title, onSuccess }: Props
38
39
  type: 'Conversation',
39
40
  attributes: {
40
41
  payload,
42
+ ...(genderId ? { gender_id: genderId } : {}),
41
43
  },
42
44
  },
43
45
  },
@@ -36,6 +36,7 @@ export function useFeatures() {
36
36
  export const availableFeatures = {
37
37
  message_reporting: 'ROLLOUT_MOBILE_message_reporting',
38
38
  granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',
39
+ gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',
39
40
  }
40
41
 
41
42
  const stableEmptyFeatures: ApiCollection<FeatureResource> = {
@@ -0,0 +1,42 @@
1
+ import { ResourceObject } from '../types/api_primitives'
2
+ import { useApiGet } from './use_api'
3
+ import { availableFeatures, useFeatures } from './use_features'
4
+
5
+ interface GenderResource extends ResourceObject {
6
+ type: 'Gender'
7
+ value: string
8
+ }
9
+
10
+ interface PersonWithGender extends ResourceObject {
11
+ type: 'Person'
12
+ gender: GenderResource | undefined
13
+ }
14
+
15
+ export function useMyGender() {
16
+ const { featureEnabled } = useFeatures()
17
+ const isFeatureEnabled = featureEnabled(availableFeatures.gender_specific_conversations)
18
+
19
+ const { data, isFetching } = useApiGet<PersonWithGender>({
20
+ url: '/me',
21
+ enabled: isFeatureEnabled,
22
+ data: {
23
+ include: ['gender'],
24
+ fields: {
25
+ Person: ['gender'],
26
+ Gender: ['value'],
27
+ },
28
+ },
29
+ app: 'people',
30
+ })
31
+
32
+ const gender = data?.gender
33
+ const genderValue = gender?.value ?? null
34
+ const genderId = gender?.id ? String(gender.id) : null
35
+
36
+ return {
37
+ isFeatureEnabled,
38
+ genderValue,
39
+ genderId,
40
+ isFetching,
41
+ }
42
+ }
@@ -0,0 +1,92 @@
1
+ import React from 'react'
2
+ import { ActivityIndicator, StyleSheet, View } from 'react-native'
3
+ import { Heading, Switch, Text } from '../../../components'
4
+ import { useTheme } from '../../../hooks'
5
+ import { genderDisplayLabel } from '../../../utils/gender_display_label'
6
+
7
+ interface FilterableGenderContentProps {
8
+ genderValue: string
9
+ enabled: boolean
10
+ onToggle: (enabled: boolean) => void
11
+ }
12
+
13
+ function FilterableGenderContent({ genderValue, enabled, onToggle }: FilterableGenderContentProps) {
14
+ const { colors } = useTheme()
15
+ const styles = useStyles()
16
+ const displayLabel = genderDisplayLabel(genderValue)
17
+
18
+ return (
19
+ <>
20
+ <View style={styles.toggleRow}>
21
+ <Text>{displayLabel}</Text>
22
+ <Switch
23
+ value={enabled}
24
+ onValueChange={onToggle}
25
+ accessibilityLabel={`Filter by ${displayLabel}`}
26
+ />
27
+ </View>
28
+ <Text style={{ color: colors.textColorDefaultSecondary }}>
29
+ Filter limited to your profile's set gender
30
+ </Text>
31
+ </>
32
+ )
33
+ }
34
+
35
+ function NoGenderContent({ isFetching }: { isFetching: boolean }) {
36
+ const { colors } = useTheme()
37
+
38
+ return (
39
+ <>
40
+ <Text>Gender</Text>
41
+ {isFetching ? (
42
+ <ActivityIndicator size="small" />
43
+ ) : (
44
+ <Text style={{ color: colors.textColorDefaultSecondary }}>
45
+ Set a gender in your Church Center profile to enable gender filtering.
46
+ </Text>
47
+ )}
48
+ </>
49
+ )
50
+ }
51
+
52
+ interface GenderFilterToggleProps {
53
+ genderValue: string | null
54
+ isFetching: boolean
55
+ enabled: boolean
56
+ onToggle: (enabled: boolean) => void
57
+ }
58
+
59
+ export function GenderFilterToggle({
60
+ genderValue,
61
+ isFetching,
62
+ enabled,
63
+ onToggle,
64
+ }: GenderFilterToggleProps) {
65
+ const styles = useStyles()
66
+ const hasFilterableGender = genderValue !== null && genderValue !== 'Prefer not to say'
67
+
68
+ return (
69
+ <View style={styles.container}>
70
+ <Heading variant="h3">Filter by</Heading>
71
+ {hasFilterableGender ? (
72
+ <FilterableGenderContent genderValue={genderValue} enabled={enabled} onToggle={onToggle} />
73
+ ) : (
74
+ <NoGenderContent isFetching={isFetching} />
75
+ )}
76
+ </View>
77
+ )
78
+ }
79
+
80
+ const useStyles = () => {
81
+ return StyleSheet.create({
82
+ container: {
83
+ padding: 16,
84
+ gap: 8,
85
+ },
86
+ toggleRow: {
87
+ flexDirection: 'row',
88
+ justifyContent: 'space-between',
89
+ alignItems: 'center',
90
+ },
91
+ })
92
+ }
@@ -13,8 +13,11 @@ import { useGroupsConversationCreate } from '../../../hooks/groups/use_groups_co
13
13
  import { GroupsGroupResource } from '../../../types'
14
14
  import { GraphId } from '../../../types/resources/group_resource'
15
15
  import { pluralize } from '../../../utils'
16
+ import { genderDisplayLabel } from '../../../utils/gender_display_label'
16
17
  import { Divider, FormList } from './form_list'
18
+ import { GenderFilterToggle } from './gender_filter_toggle'
17
19
  import { Haptic } from '../../../utils/native_adapters'
20
+ import { useMyGender } from '../../../hooks/use_my_gender'
18
21
 
19
22
  type GroupsFormProps = {
20
23
  groupId: number
@@ -23,7 +26,14 @@ type GroupsFormProps = {
23
26
 
24
27
  export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) => {
25
28
  const navigation = useNavigation()
26
- const [title, setTitle] = useState<string>()
29
+ const [title, setTitle] = useState('')
30
+ const [genderFilterEnabled, setGenderFilterEnabled] = useState(false)
31
+ const {
32
+ isFeatureEnabled: genderFilterAvailable,
33
+ genderId,
34
+ genderValue,
35
+ isFetching: genderFetching,
36
+ } = useMyGender()
27
37
  const { data: group } = useSuspenseGet<GroupsGroupResource>({
28
38
  url: `/me/groups/${groupId}`,
29
39
  data: {
@@ -36,6 +46,23 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
36
46
 
37
47
  const groupMemberships = useGroupMembersForNewConversation({ id: groupId })
38
48
 
49
+ const activeGenderId = genderFilterEnabled ? genderId : null
50
+
51
+ const handleGenderToggle = (enabled: boolean) => {
52
+ const displayLabel = genderValue ? genderDisplayLabel(genderValue) : ''
53
+ const defaultTitle = `${group.name} (${displayLabel})`
54
+ const shouldAutoPopulateTitle = enabled && genderValue && title === ''
55
+ const shouldClearAutoPopulatedTitle = !enabled && title === defaultTitle
56
+
57
+ setGenderFilterEnabled(enabled)
58
+
59
+ if (shouldAutoPopulateTitle) {
60
+ setTitle(defaultTitle)
61
+ } else if (shouldClearAutoPopulatedTitle) {
62
+ setTitle('')
63
+ }
64
+ }
65
+
39
66
  const redirectToConversation = useCallback(
40
67
  (conversationId: number) => {
41
68
  // navigate to the conversation screen
@@ -53,6 +80,7 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
53
80
  const { mutate: handleSave, isPending } = useGroupsConversationCreate({
54
81
  groupId,
55
82
  title,
83
+ genderId: activeGenderId,
56
84
  onSuccess: redirectToConversation,
57
85
  })
58
86
 
@@ -67,6 +95,11 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
67
95
  group={group}
68
96
  title={title}
69
97
  setTitle={setTitle}
98
+ genderFilterAvailable={genderFilterAvailable}
99
+ genderFilterEnabled={genderFilterEnabled}
100
+ genderValue={genderValue}
101
+ genderFetching={genderFetching}
102
+ onGenderToggle={handleGenderToggle}
70
103
  groupMemberships={groupMemberships}
71
104
  />
72
105
  }
@@ -83,12 +116,27 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
83
116
 
84
117
  interface FormContentProps {
85
118
  group: GroupsGroupResource
86
- title?: string
119
+ title: string
87
120
  setTitle: (title: string) => void
121
+ genderFilterAvailable: boolean
122
+ genderFilterEnabled: boolean
123
+ genderValue: string | null
124
+ genderFetching: boolean
125
+ onGenderToggle: (enabled: boolean) => void
88
126
  groupMemberships: GroupMembersForNewConversationResult
89
127
  }
90
128
 
91
- function FormContent({ group, title, setTitle, groupMemberships }: FormContentProps) {
129
+ function FormContent({
130
+ group,
131
+ title,
132
+ setTitle,
133
+ genderFilterAvailable,
134
+ genderFilterEnabled,
135
+ genderValue,
136
+ genderFetching,
137
+ onGenderToggle,
138
+ groupMemberships,
139
+ }: FormContentProps) {
92
140
  const styles = useStyles()
93
141
  const inputRef = useRef<TextInput>(null)
94
142
  const currentPerson = useCurrentPerson()
@@ -129,6 +177,17 @@ function FormContent({ group, title, setTitle, groupMemberships }: FormContentPr
129
177
  />
130
178
  </Pressable>
131
179
  <Divider />
180
+ {genderFilterAvailable && (
181
+ <>
182
+ <GenderFilterToggle
183
+ genderValue={genderValue}
184
+ isFetching={genderFetching}
185
+ enabled={genderFilterEnabled}
186
+ onToggle={onGenderToggle}
187
+ />
188
+ <Divider />
189
+ </>
190
+ )}
132
191
  <View style={styles.memberSection}>
133
192
  <Heading variant="h3">{memberHeaderLabel}</Heading>
134
193
  {hasChildren && (
@@ -0,0 +1,10 @@
1
+ export function genderDisplayLabel(genderOption: string): string {
2
+ switch (genderOption) {
3
+ case 'Male':
4
+ return 'Men'
5
+ case 'Female':
6
+ return 'Women'
7
+ default:
8
+ return genderOption
9
+ }
10
+ }