Browse Source

FEATURE | Create settings screen

pull/3/head
Vlad Narizhnyi 1 year ago
parent
commit
e04efecaa0
  1. 9
      App.tsx
  2. 6
      ios/Podfile.lock
  3. 83
      package-lock.json
  4. 4
      package.json
  5. BIN
      src/assets/icons/ENG.png
  6. BIN
      src/assets/icons/UAE.png
  7. BIN
      src/assets/icons/UKR.png
  8. 0
      src/i18n/interfaces/buttons.interface.ts
  9. 8
      src/i18n/interfaces/common.interface.ts
  10. 0
      src/i18n/interfaces/custom-pack.interface.ts
  11. 15
      src/i18n/interfaces/index.ts
  12. 0
      src/i18n/interfaces/on-boarding.types.interface.ts
  13. 0
      src/i18n/interfaces/page-titles.interface.ts
  14. 12
      src/i18n/interfaces/settings.types.interface.ts
  15. 11
      src/i18n/locales/en/common.translation.ts
  16. 7
      src/i18n/locales/en/custom-pack.translation.ts
  17. 27
      src/i18n/locales/en/index.ts
  18. 10
      src/i18n/locales/en/page-title.translation.ts
  19. 21
      src/i18n/locales/en/settings.translation.ts
  20. 35
      src/i18n/locales/en/steps.translation.ts
  21. 24
      src/i18n/locales/hi/index.tsx
  22. 20
      src/i18n/locales/hi/settings.translation.ts
  23. 35
      src/i18n/locales/hi/steps.translation.ts
  24. 11
      src/i18n/locales/ua/common.translation.ts
  25. 27
      src/i18n/locales/ua/index.ts
  26. 10
      src/i18n/locales/ua/page-title.translation.ts
  27. 23
      src/i18n/locales/ua/settings.translation.ts
  28. 12
      src/i18n/types/index.ts
  29. 12
      src/i18n/types/settings.types.ts
  30. 7
      src/module/common/components/buttons/button-primary.component.tsx
  31. 60
      src/module/common/components/form/form-controll-wrap.component.tsx
  32. 117
      src/module/common/components/form/form-text-controll.component.tsx
  33. 3
      src/module/common/components/form/index.ts
  34. 14
      src/module/common/components/index.ts
  35. 10
      src/module/common/components/layout/screen-layout.component.tsx
  36. 1
      src/module/common/hooks/index.ts
  37. 67
      src/module/common/hooks/use-form.hook.ts
  38. 1
      src/module/common/tools/index.ts
  39. 67
      src/module/common/tools/validate.tool.ts
  40. 10
      src/module/common/typing/enums/route-keys.enum.ts
  41. 2
      src/module/common/typing/interfaces/index.ts
  42. 2
      src/module/common/widgets/alert/alert-widget.component.tsx
  43. 24
      src/module/common/widgets/bottom-sheet/atoms/action-sheet-button.atom.tsx
  44. 23
      src/module/common/widgets/bottom-sheet/atoms/bottom-sheet-view.atom.tsx
  45. 1
      src/module/common/widgets/bottom-sheet/atoms/index.ts
  46. 1
      src/module/common/widgets/bottom-sheet/index.ts
  47. 1
      src/module/common/widgets/index.ts
  48. 2
      src/module/game/screens/game.screen.tsx
  49. 2
      src/module/game/screens/questions.screen.tsx
  50. 2
      src/module/packages/screens/packages-list.screen.tsx
  51. 2
      src/module/root/atoms/on-boarding-button.component.tsx
  52. 2
      src/module/root/config/on-boarding.config.ts
  53. 45
      src/module/root/navigations-groups/user.group.tsx
  54. 2
      src/module/root/screens/language-select.screen.tsx
  55. 2
      src/module/root/screens/loading-screen.tsx
  56. 3
      src/module/settings/atoms/index.ts
  57. 40
      src/module/settings/atoms/selected-language-in-settings.atom.tsx
  58. 22
      src/module/settings/atoms/switch-notifications.atom.tsx
  59. 30
      src/module/settings/components/settings-item.component.tsx
  60. 13
      src/module/settings/config/settings.config.tsx
  61. 1
      src/module/settings/index.ts
  62. 2
      src/module/settings/screens/index.ts
  63. 43
      src/module/settings/screens/purchases.screen.tsx
  64. 90
      src/module/settings/screens/settings.screen.tsx
  65. 67
      src/module/settings/screens/write-to-us.screen.tsx
  66. 1
      src/module/settings/validator/index.ts
  67. 15
      src/module/settings/validator/writeToUs.validator.ts

9
App.tsx

@ -10,6 +10,7 @@ import { @@ -10,6 +10,7 @@ import {
SafeAreaProvider,
initialWindowMetrics,
} from 'react-native-safe-area-context'
import { SheetProvider } from 'react-native-actions-sheet'
const App = () => {
useEffect(() => {
@ -20,9 +21,11 @@ const App = () => { @@ -20,9 +21,11 @@ const App = () => {
<GestureHandlerRootView style={{ flex: 1 }}>
<NavigationContainer>
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<Provider store={store}>
<Root />
</Provider>
<SheetProvider>
<Provider store={store}>
<Root />
</Provider>
</SheetProvider>
</SafeAreaProvider>
</NavigationContainer>
</GestureHandlerRootView>

6
ios/Podfile.lock

@ -1271,6 +1271,8 @@ PODS: @@ -1271,6 +1271,8 @@ PODS:
- nanopb (< 2.30910.0, >= 2.30908.0)
- React-Core
- RNFBApp
- RNFlashList (1.6.3):
- React-Core
- RNGestureHandler (2.13.4):
- RCT-Folly (= 2021.07.22.00)
- React-Core
@ -1358,6 +1360,7 @@ DEPENDENCIES: @@ -1358,6 +1360,7 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBFirestore (from `../node_modules/@react-native-firebase/firestore`)"
- "RNFlashList (from `../node_modules/@shopify/flash-list`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
@ -1485,6 +1488,8 @@ EXTERNAL SOURCES: @@ -1485,6 +1488,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-firebase/app"
RNFBFirestore:
:path: "../node_modules/@react-native-firebase/firestore"
RNFlashList:
:path: "../node_modules/@shopify/flash-list"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNScreens:
@ -1568,6 +1573,7 @@ SPEC CHECKSUMS: @@ -1568,6 +1573,7 @@ SPEC CHECKSUMS:
RNCAsyncStorage: f2974eca860c16a3e56eea5771fda8d12e2d2057
RNFBApp: 0d8bf86673bbad0524d1ceac3944d71ccf48a0e4
RNFBFirestore: f16efbd47cd136fe84cb93dc87ad4155807db221
RNFlashList: 4b4b6b093afc0df60ae08f9cbf6ccd4c836c667a
RNGestureHandler: 6e46dde1f87e5f018a54fe5d40cd0e0b942b49ee
RNScreens: 3c2d122f5e08c192e254c510b212306da97d2581
RNSVG: d7d7bc8229af3842c9cfc3a723c815a52cdd1105

83
package-lock.json generated

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
"@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0",
"@reduxjs/toolkit": "^1.9.2",
"@shopify/flash-list": "^1.6.3",
"i18next": "^21.8.14",
"i18next-react-native-async-storage": "^1.0.4",
"jet-tools": "^1.3.0",
@ -34,7 +35,8 @@ @@ -34,7 +35,8 @@
"react-native-svg": "^12.5.1",
"react-native-svg-transformer": "^1.0.0",
"react-native-vector-icons": "^9.2.0",
"react-redux": "^8.0.5"
"react-redux": "^8.0.5",
"validate.js": "^0.13.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@ -4292,6 +4294,25 @@ @@ -4292,6 +4294,25 @@
}
}
},
"node_modules/@shopify/flash-list": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz",
"integrity": "sha512-XM2iu4CeD9SOEUxaGG3UkxfUxGPWG9yacga1yQSgskAjUsRDFTsD3y4Dyon9n8MfDwgrRpEwuijd+7NeQQoWaQ==",
"dependencies": {
"recyclerlistview": "4.2.0",
"tslib": "2.4.0"
},
"peerDependencies": {
"@babel/runtime": "*",
"react": "*",
"react-native": "*"
}
},
"node_modules/@shopify/flash-list/node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@ -13262,6 +13283,20 @@ @@ -13262,6 +13283,20 @@
"node": ">= 4"
}
},
"node_modules/recyclerlistview": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.0.tgz",
"integrity": "sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==",
"dependencies": {
"lodash.debounce": "4.0.8",
"prop-types": "15.8.1",
"ts-object-utils": "0.0.5"
},
"peerDependencies": {
"react": ">= 15.2.1",
"react-native": ">= 0.30.0"
}
},
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
@ -14336,6 +14371,11 @@ @@ -14336,6 +14371,11 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-object-utils": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@ -14646,6 +14686,11 @@ @@ -14646,6 +14686,11 @@
"node": ">=10.12.0"
}
},
"node_modules/validate.js": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/validate.js/-/validate.js-0.13.1.tgz",
"integrity": "sha512-PnFM3xiZ+kYmLyTiMgTYmU7ZHkjBZz2/+F0DaALc/uUtVzdCt1wAosvYJ5hFQi/hz8O4zb52FQhHZRC+uVkJ+g=="
},
"node_modules/validatorjs": {
"version": "3.22.1",
"resolved": "https://registry.npmjs.org/validatorjs/-/validatorjs-3.22.1.tgz",
@ -17961,6 +18006,22 @@ @@ -17961,6 +18006,22 @@
"reselect": "^4.1.8"
}
},
"@shopify/flash-list": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz",
"integrity": "sha512-XM2iu4CeD9SOEUxaGG3UkxfUxGPWG9yacga1yQSgskAjUsRDFTsD3y4Dyon9n8MfDwgrRpEwuijd+7NeQQoWaQ==",
"requires": {
"recyclerlistview": "4.2.0",
"tslib": "2.4.0"
},
"dependencies": {
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
}
}
},
"@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@ -24479,6 +24540,16 @@ @@ -24479,6 +24540,16 @@
"tslib": "^2.0.1"
}
},
"recyclerlistview": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.0.tgz",
"integrity": "sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==",
"requires": {
"lodash.debounce": "4.0.8",
"prop-types": "15.8.1",
"ts-object-utils": "0.0.5"
}
},
"redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
@ -25309,6 +25380,11 @@ @@ -25309,6 +25380,11 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"ts-object-utils": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
},
"tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@ -25520,6 +25596,11 @@ @@ -25520,6 +25596,11 @@
"convert-source-map": "^2.0.0"
}
},
"validate.js": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/validate.js/-/validate.js-0.13.1.tgz",
"integrity": "sha512-PnFM3xiZ+kYmLyTiMgTYmU7ZHkjBZz2/+F0DaALc/uUtVzdCt1wAosvYJ5hFQi/hz8O4zb52FQhHZRC+uVkJ+g=="
},
"validatorjs": {
"version": "3.22.1",
"resolved": "https://registry.npmjs.org/validatorjs/-/validatorjs-3.22.1.tgz",

4
package.json

@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
"@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0",
"@reduxjs/toolkit": "^1.9.2",
"@shopify/flash-list": "^1.6.3",
"i18next": "^21.8.14",
"i18next-react-native-async-storage": "^1.0.4",
"jet-tools": "^1.3.0",
@ -41,7 +42,8 @@ @@ -41,7 +42,8 @@
"react-native-svg": "^12.5.1",
"react-native-svg-transformer": "^1.0.0",
"react-native-vector-icons": "^9.2.0",
"react-redux": "^8.0.5"
"react-redux": "^8.0.5",
"validate.js": "^0.13.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",

BIN
src/assets/icons/ENG.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

BIN
src/assets/icons/UAE.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

BIN
src/assets/icons/UKR.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

0
src/i18n/types/buttons.types.ts → src/i18n/interfaces/buttons.interface.ts

8
src/i18n/interfaces/common.interface.ts

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
interface Validation {
isRequire: string
}
export interface Common {
validate: Validation
shareMessage: string
}

0
src/module/common/typing/interfaces/custom-pack.ts → src/i18n/interfaces/custom-pack.interface.ts

15
src/i18n/interfaces/index.ts

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
import { Buttons } from './buttons.interface'
import { Common } from './common.interface'
import { CustomPack } from './custom-pack.interface'
import { OnBoardingLocale } from './on-boarding.types.interface'
import { PageTitles } from './page-titles.interface'
import { SettingLocale } from './settings.types.interface'
export interface MainLocaleModule {
stepTranslation: OnBoardingLocale.OnboardingSteps
settingTranslation: SettingLocale.Core
buttonsTranslation: Buttons
customPack: CustomPack
pageTitles: PageTitles
common: Common
}

0
src/i18n/types/on-boarding.types.ts → src/i18n/interfaces/on-boarding.types.interface.ts

0
src/module/common/typing/interfaces/page-titles.ts → src/i18n/interfaces/page-titles.interface.ts

12
src/i18n/interfaces/settings.types.interface.ts

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
export namespace SettingLocale {
export interface Core {
purchases: string
language: string
notifications: string
write: string
rate: string
share: string
policy: string
label: string
}
}

11
src/i18n/locales/en/common.translation.ts

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
import { Common } from '../../interfaces/common.interface'
const Validation = {
isRequire: 'Field is require',
length: 'At least 5 characters',
}
export const common: Common = {
validate: Validation,
shareMessage: 'Share this app with your friends',
}

7
src/i18n/locales/en/custom-pack.translation.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
export const customPack = {
title: 'Create custom pack',
description: 'Create your own custom pack with questions and task. It all depends on your imagination!',
}
title: 'Create custom pack',
description:
'Create your own custom pack with questions and task. It all depends on your imagination!',
}

27
src/i18n/locales/en/index.ts

@ -1,13 +1,16 @@ @@ -1,13 +1,16 @@
import {MainLocaleModule} from '../../types';
import {settingTranslation} from './settings.translation';
import {onBoardingTranslation} from './steps.translation';
import {buttonsTranslation} from './onBoardingButton.translation';
import {customPack} from './custom-pack.translation';
import {pageTitles} from './page-title.translation';
import { MainLocaleModule } from '../../interfaces'
import { settingTranslation } from './settings.translation'
import { onBoardingTranslation } from './steps.translation'
import { buttonsTranslation } from './onBoardingButton.translation'
import { customPack } from './custom-pack.translation'
import { pageTitles } from './page-title.translation'
import { common } from './common.translation'
export const en: MainLocaleModule = {
settingTranslation,
stepTranslation: onBoardingTranslation,
buttonsTranslation,
customPack,
pageTitles,
};
settingTranslation,
stepTranslation: onBoardingTranslation,
buttonsTranslation,
customPack,
pageTitles,
common,
}

10
src/i18n/locales/en/page-title.translation.ts

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
export const pageTitles = {
setting: 'Setting',
privacy: 'Privacy Policy',
terms: 'Terms and conditions',
}
setting: 'Setting',
purchases: 'Purchases',
privacy: 'Privacy Policy',
terms: 'Terms and conditions',
writeToUs: 'Write to us',
}

21
src/i18n/locales/en/settings.translation.ts

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
import {SettingLocale} from '../../types/settings.types';
import { SettingLocale } from '../../interfaces/settings.types.interface'
export const settingTranslation: SettingLocale.Core = {
purchases: 'Purchases!',
language: 'Language',
write: 'Write to us',
rate: 'Rate us',
share: 'Share app',
policy: 'Privacy policy',
term: 'Terms and conditions',
information: 'Information',
};
purchases: 'Purchases!',
language: 'Language',
notifications: 'Notifications',
write: 'Write to us',
rate: 'Rate us',
share: 'Share app',
policy: 'Privacy policy',
label: 'What can we do to help?',
}

35
src/i18n/locales/en/steps.translation.ts

@ -1,19 +1,18 @@ @@ -1,19 +1,18 @@
import {OnBoardingLocale} from '../../types/on-boarding.types';
import { OnBoardingLocale } from '../../interfaces/on-boarding.types.interface'
export const onBoardingTranslation: OnBoardingLocale.OnboardingSteps = {
step1: {
title: 'Welcome!',
description:
'Thank you for downloading. Now you are \n in the best game for the company \n or to play with your loved one',
},
step2: {
title: 'Relax and enjoy \n the game!',
description:
'This game features 5 levels of "spiciness",\n some of which are divided into games for a \n couple or a company. All you have to do is \n add players and you can start playing.\n P.S. You can always create your own \n questions and tasks.',
},
step3: {
title: 'Premium version!',
description:
'Provides unlimited access to Hard and \n Extreme packages. Enjoy intriguing questions \n and exciting action.',
},
};
step1: {
title: 'Welcome!',
description:
'Thank you for downloading. Now you are \n in the best game for the company \n or to play with your loved one',
},
step2: {
title: 'Relax and enjoy \n the game!',
description:
'This game features 5 levels of "spiciness",\n some of which are divided into games for a \n couple or a company. All you have to do is \n add players and you can start playing.\n P.S. You can always create your own \n questions and tasks.',
},
step3: {
title: 'Premium version!',
description:
'Provides unlimited access to Hard and \n Extreme packages. Enjoy intriguing questions \n and exciting action.',
},
}

24
src/i18n/locales/hi/index.tsx

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
import {MainLocaleModule} from '../../types';
import {settingTranslation} from './settings.translation';
import {onBoardingTranslation} from './steps.translation';
import { buttonsTranslation } from './onBoardingButton.translation';
import {customPack} from './custom-pack.translation';
import {pageTitles} from './page-title.translation';
import { MainLocaleModule } from '../../interfaces'
import { settingTranslation } from './settings.translation'
import { onBoardingTranslation } from './steps.translation'
import { buttonsTranslation } from './onBoardingButton.translation'
import { customPack } from './custom-pack.translation'
import { pageTitles } from './page-title.translation'
export const hi: MainLocaleModule = {
settingTranslation,
stepTranslation: onBoardingTranslation,
buttonsTranslation,
customPack,
pageTitles,
};
settingTranslation,
stepTranslation: onBoardingTranslation,
buttonsTranslation,
customPack,
pageTitles,
}

20
src/i18n/locales/hi/settings.translation.ts

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
import {SettingLocale} from '../../types/settings.types';
import { SettingLocale } from '../../interfaces/settings.types.interface'
export const settingTranslation: SettingLocale.Core = {
purchases: 'खरद!',
language: 'भ',
write: 'हमि',
rate: 'हमिग द',
share: 'ऐप शयर कर',
policy: 'गपनयति',
term: 'नियम और शर',
information: 'जनक',
};
purchases: 'खरद!',
language: 'भ',
write: 'हमि',
rate: 'हमिग द',
share: 'ऐप शयर कर',
policy: 'गपनयति',
term: 'नियम और शर',
information: 'जनक',
}

35
src/i18n/locales/hi/steps.translation.ts

@ -1,19 +1,18 @@ @@ -1,19 +1,18 @@
import {OnBoardingLocale} from '../../types/on-boarding.types';
import { OnBoardingLocale } from '../../interfaces/on-boarding.types.interface'
export const onBoardingTranslation: OnBoardingLocale.OnboardingSteps = {
step1: {
title: 'सगत!',
description:
'डउनलड करनिए धनयवद। अब आप \n कपनिए सरवशठ गम म \n य अपनियजन कथ खलनिए',
},
step2: {
title: 'आरम कर और \n खल क आनद ल!',
description:
'इस गम म "मसरत" क 5 सतर ह, जिनमछ क \n जपनिए गम मिित कि गय। आपक बस इतन करनि \n खि और आप खलन कर सकत। प.एस. आप हम अपनरशन और कय बन सकत।',
},
step3: {
title: 'पियम सकरण!',
description:
'हड और \n एकसटम पज तक असित पहच परदन करत। दिलचसप सव \n और रचक एकशन क आनद ल।',
},
};
step1: {
title: 'सगत!',
description:
'डउनलड करनिए धनयवद। अब आप \n कपनिए सरवशठ गम म \n य अपनियजन कथ खलनिए',
},
step2: {
title: 'आरम कर और \n खल क आनद ल!',
description:
'इस गम म "मसरत" क 5 सतर ह, जिनमछ क \n जपनिए गम मिित कि गय। आपक बस इतन करनि \n खि और आप खलन कर सकत। प.एस. आप हम अपनरशन और कय बन सकत।',
},
step3: {
title: 'पियम सकरण!',
description:
'हड और \n एकसटम पज तक असित पहच परदन करत। दिलचसप सव \n और रचक एकशन क आनद ल।',
},
}

11
src/i18n/locales/ua/common.translation.ts

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
import { Common } from '../../interfaces/common.interface'
const Validation = {
isRequire: 'Це поле обовʼязкове',
length: 'Має бути мінімум 5 символів',
}
export const common: Common = {
validate: Validation,
shareMessage: 'Поділіться цим додатком зі своїми друзями',
}

27
src/i18n/locales/ua/index.ts

@ -1,15 +1,16 @@ @@ -1,15 +1,16 @@
import {MainLocaleModule} from '../../types';
import {settingTranslation} from './settings.translation';
import {onBoardingTranslationUa} from './step.translation';
import { buttonsTranslation } from './onBoardingButton.translation';
import {customPack} from './custom-pack.translation';
import {pageTitles} from './page-title.translation';
import { MainLocaleModule } from '../../interfaces'
import { settingTranslation } from './settings.translation'
import { onBoardingTranslationUa } from './step.translation'
import { buttonsTranslation } from './onBoardingButton.translation'
import { customPack } from './custom-pack.translation'
import { pageTitles } from './page-title.translation'
import { common } from './common.translation'
export const ua: MainLocaleModule = {
stepTranslation: onBoardingTranslationUa,
settingTranslation: settingTranslation,
buttonsTranslation,
customPack,
pageTitles
};
stepTranslation: onBoardingTranslationUa,
settingTranslation,
buttonsTranslation,
customPack,
pageTitles,
common,
}

10
src/i18n/locales/ua/page-title.translation.ts

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
export const pageTitles = {
setting: 'Налаштування',
privacy: 'Політика \n конфіденційності',
terms: 'Правила та умови',
}
purchases: 'Покупки',
setting: 'Налаштування',
privacy: 'Політика \n конфіденційності',
terms: 'Правила та умови',
writeToUs: 'Напишіть нам',
}

23
src/i18n/locales/ua/settings.translation.ts

@ -1,11 +1,14 @@ @@ -1,11 +1,14 @@
import {SettingLocale} from '../../types/settings.types';
import { SettingLocale } from '../../interfaces/settings.types.interface'
export const settingTranslation: SettingLocale.Core = {
purchases: 'Магазин!',
language: 'Мова',
write: 'Напишіть нам',
rate: 'Оцініть нас',
share: 'Поділитися програмою',
policy: 'Політика конфіденційності',
term: 'Правила та умови',
information: 'Інформація',
};
purchases: 'Магазин',
language: 'Мова',
notifications: 'Сповіщення',
write: 'Напишіть нам',
rate: 'Оцініть нас',
share: 'Поділитися програмою',
policy: 'Політика конфіденційності',
term: 'Правила та умови',
information: 'Інформація',
label: 'Чим ми можемо допомогти',
}

12
src/i18n/types/index.ts

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
import { CustomPack, PageTitles } from '../../module/common'
import { Buttons } from './buttons.types'
import { OnBoardingLocale } from './on-boarding.types'
import { SettingLocale } from './settings.types'
export interface MainLocaleModule {
stepTranslation: OnBoardingLocale.OnboardingSteps
settingTranslation: SettingLocale.Core
buttonsTranslation: Buttons
customPack: CustomPack
pageTitles: PageTitles
}

12
src/i18n/types/settings.types.ts

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
export namespace SettingLocale {
export interface Core {
purchases: string;
language: string;
write: string;
rate: string;
share: string;
policy: string;
term: string;
information: string;
}
}

7
src/module/common/components/buttons/button-primary.component.tsx

@ -60,7 +60,12 @@ export const ButtonPrimary: FC<PropsWithChildren<IButtonPrimaryProps>> = ({ @@ -60,7 +60,12 @@ export const ButtonPrimary: FC<PropsWithChildren<IButtonPrimaryProps>> = ({
activeOpacity={0.6}
disabled={disabled}
onPress={onPress}
style={[styles.container, style, { marginBottom: mb, width }]}>
style={[
styles.container,
style,
{ marginBottom: mb, width },
disabled && { backgroundColor: colors.blue },
]}>
<Txt
font={txtFont}
mod={txtMod}

60
src/module/common/components/form/form-controll-wrap.component.tsx

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
import React, { FC, PropsWithChildren } from 'react'
import { StyleSheet, View, ViewStyle } from 'react-native'
import { Txt } from '../txt'
import { $size } from '../../helpers'
import { colors } from '../../colors'
interface FormControllWrapProps {
label?: string
error?: string
style?: ViewStyle
rightLabel?: string
}
export const FormControllWrap: FC<PropsWithChildren<FormControllWrapProps>> = ({
label,
error,
children,
style,
rightLabel,
}) => {
return (
<View style={[styles.container, style]}>
<View style={styles.labelWrap}>
{label ? (
<Txt mod="lg" style={styles.label}>
{label}
</Txt>
) : null}
{rightLabel ? (
<Txt style={styles.label}>{rightLabel}</Txt>
) : null}
</View>
{children}
{error ? <Txt style={styles.error}>{error}</Txt> : null}
</View>
)
}
const styles = StyleSheet.create({
container: {
marginBottom: $size(12),
width: '100%',
},
labelWrap: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: $size(5),
},
label: {
color: colors.secondaryText,
marginBottom: $size(8),
},
error: {
color: colors.red,
fontSize: $size(13),
marginTop: $size(5),
},
})

117
src/module/common/components/form/form-text-controll.component.tsx

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
import React, { FC } from 'react'
import {
StyleSheet,
TextInput,
TextInputProps,
View,
ViewStyle,
} from 'react-native'
import { Txt } from '../txt'
import { FormControllWrap } from './form-controll-wrap.component'
import { Font } from '../../typing'
import { $size } from '../../helpers'
import { colors } from '../../colors'
interface FormTextControllProps {
value: string
onChange: (value: string) => void
inputProps?: Omit<TextInputProps, 'value' | 'onChange'>
label?: string
error?: string
postfix?: string
subtext?: string
inputStyle?: ViewStyle
style?: ViewStyle
}
export const FormTextControll: FC<FormTextControllProps> = ({
value,
onChange,
inputProps = {},
label,
error,
postfix,
subtext,
inputStyle,
style,
}) => {
const renderPostfix = () => {
if (postfix)
return (
<View style={styles.rightComponent}>
<Txt style={styles.postfix}>{postfix}</Txt>
</View>
)
}
return (
<FormControllWrap label={label} error={error} style={style}>
<View style={styles.inputContainer}>
<TextInput
style={[
styles.input,
error ? styles.inputActive : null,
inputStyle,
]}
value={value}
onChangeText={onChange}
placeholderTextColor="#A0A3BD"
{...inputProps}
/>
{renderPostfix()}
</View>
{subtext ? <Txt style={styles.subtext}>{subtext}</Txt> : null}
</FormControllWrap>
)
}
const styles = StyleSheet.create({
containerActive: {
borderColor: '#FB5450',
},
inputContainer: {
position: 'relative',
paddingRight: 1,
},
input: {
borderColor: colors.secondaryText,
borderWidth: 1,
height: $size(50),
paddingHorizontal: $size(18),
borderRadius: 16,
color: colors.textPrimary,
fontFamily: Font.Roboto400,
fontSize: $size(15),
lineHeight: $size(20),
},
inputActive: {
borderColor: '#FB5450',
},
rightComponent: {
position: 'absolute',
right: 0,
top: 0,
height: 56,
justifyContent: 'center',
alignItems: 'center',
paddingRight: 20,
// width: 100,
},
postfix: {
color: '#9693AC',
fontSize: $size(15),
},
subtext: {
color: '#808080',
fontSize: $size(12),
marginBottom: 4,
},
})

3
src/module/common/components/form/index.ts

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
export * from './form-controll-wrap.component';
export * from './form-text-controll.component';

14
src/module/common/components/index.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
export * from './icon';
export * from './buttons';
export * from './header';
export * from './layout';
export * from './modal';
export * from './txt';
export * from './icon'
export * from './buttons'
export * from './header'
export * from './layout'
export * from './modal'
export * from './txt'
export * from './form'

10
src/module/common/components/layout/screen-layout.component.tsx

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import React, { ReactElement } from 'react'
import {
ColorValue,
Platform,
StatusBar,
StyleSheet,
View,
@ -49,6 +50,14 @@ export const ScreenLayout = ({ @@ -49,6 +50,14 @@ export const ScreenLayout = ({
$size(44),
)
const safeAreaLayOut = () => {
if (bottomSafeArea) {
return insets.bottom + 5
} else {
return 0
}
}
return (
<>
<View
@ -70,6 +79,7 @@ export const ScreenLayout = ({ @@ -70,6 +79,7 @@ export const ScreenLayout = ({
background,
colors.primaryColor,
),
paddingBottom: safeAreaLayOut(),
},
]}>
<ScreenLayoutContent

1
src/module/common/hooks/index.ts

@ -2,3 +2,4 @@ export * from './use-nav.hook' @@ -2,3 +2,4 @@ export * from './use-nav.hook'
export * from './use-dispatch.hook'
export * from './use-events-listener.hook'
export * from './use-selector.hook'
export * from './use-form.hook'

67
src/module/common/hooks/use-form.hook.ts

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
import _ from 'lodash'
import React, { useState } from 'react'
export interface IUseFormState {
[key: string]: string | number | boolean | any
}
type IValidateMethod<T> = (data: T) => FormErrors<T> | null
export type FormErrors<T> = Partial<Record<keyof T, string>>
export interface IForm<T> {
values: T
setForm: (form: T) => void
errors: FormErrors<T>
setFormField: (key: keyof T, value: any) => any
setFormError: (key: keyof T, error: string) => void
setFormErrors: (errors: Record<keyof T, string>) => void
onSubmit: (callback: Function) => Function
hasErrors: Boolean
}
export const useForm = <T extends IUseFormState>(
initValue: Partial<T>,
validateMethod: IValidateMethod<T>,
): IForm<T> => {
const [values, setForm] = useState(initValue as T)
const [errors, setErrors] = useState<FormErrors<T>>({})
const setFormError = (f: keyof T, e: any) => {
setErrors(oldErrors => {
return { ...oldErrors, [f]: e }
})
}
const setFormField = (f: keyof T, v: any) => {
setForm(oldForm => {
return { ...oldForm, [f]: v }
})
setFormError(f, null)
}
const validate = () => {
const _errors = validateMethod(values)
if (_errors) {
setErrors(_errors)
return true
}
}
const onSubmit = (callback: Function): any => {
if (validate && validate()) {
return
}
callback()
}
return {
values,
setForm,
errors,
setFormField,
setFormError,
setFormErrors: setErrors,
onSubmit,
hasErrors: !_.isEmpty(_.omitBy(errors, _.isNil)),
}
}

1
src/module/common/tools/index.ts

@ -1 +1,2 @@ @@ -1 +1,2 @@
export * from './global-container.tool'
export * from './validate.tool'

67
src/module/common/tools/validate.tool.ts

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
import _ from 'lodash'
import _validate from 'validate.js'
export const prepareValidatorResult = <T extends Record<string, any>>(
result: T,
): Record<keyof T, string> | null => {
if (_.isEmpty(result)) {
return null
}
_.each(result, (it, key, arr: any) => {
arr[key] = it[0]
})
return result
}
const presenceCost = {
allowEmpty: false,
message: '^Field is required',
messageStatic: '^Field is required',
}
const validate = <T extends Record<string, any>>(
values: T,
constraints: any,
) => {
const result = _validate(values, constraints)
return prepareValidatorResult<T>(result)
}
_validate.validators.array = (
arrayItems: any[],
options: { length: number; message: string; key?: string },
) => {
if (_.isEmpty(arrayItems)) {
return presenceCost.message
}
if (arrayItems.length < options.length) {
return options.message
}
if (options.key) {
if (!arrayItems[0][options.key]) {
return options.message
}
}
return null
}
_validate.validators.characters = (
value: string,
options: {
message: string
},
) => {
if (String(value).search(/[^a-zA-Zа-яА-я0-9а-яієїйьЇІ"'.)(, -]+/) !== -1) {
return options.message
? options.message
: '^common.validations.characters'
}
return null
}
export { validate, presenceCost }

10
src/module/common/typing/enums/route-keys.enum.ts

@ -1,10 +1,16 @@ @@ -1,10 +1,16 @@
export enum RouteKey {
Onboarding = 'Onboarding',
LanguageSelect = 'LanguageSelect',
Setting = 'Setting',
SettingsGroup = 'SettingsGroup',
Game = 'Game',
Loading = 'Loading',
Package = 'Package',
Packages = 'Packages',
Questions = 'Questions',
}
export enum SettingsKey {
Settings = 'Settings',
PrivacyPolicy = 'PrivacyPolicy',
Purchases = 'Purchases',
WriteToUs = 'WriteToUs'
}

2
src/module/common/typing/interfaces/index.ts

@ -1,5 +1,3 @@ @@ -1,5 +1,3 @@
export * from './custom-pack'
export * from './dare'
export * from './game-item'
export * from './page-titles'
export * from './truth'

2
src/module/common/widgets/alert/alert-widget.component.tsx

@ -32,7 +32,7 @@ export const AlertWidget = () => { @@ -32,7 +32,7 @@ export const AlertWidget = () => {
'alert',
data => {
settingsRef.current = {
onClose: () => data?.onClose,
onClose: data?.onClose as any,
}
setContent({
title: data?.title,

24
src/module/common/widgets/bottom-sheet/atoms/action-sheet-button.atom.tsx

@ -2,27 +2,32 @@ import _ from 'lodash' @@ -2,27 +2,32 @@ import _ from 'lodash'
import React, { FC } from 'react'
import { StyleSheet } from 'react-native'
import { TouchableOpacity } from 'react-native'
import { Icon } from '~modules/common'
import { Txt } from '~modules/common/components/typography'
import { $size } from '~modules/common/helpers'
import { Icon, Txt } from '../../../components'
import { $size } from '../../../helpers'
import { colors } from '../../../colors'
interface IProps {
iconName: string
icon?: () => React.ReactElement
onPress: () => void
label: string
showBottomBorder: boolean
}
export const ActionSheetButtonAtom: FC<IProps> = ({
iconName,
icon,
onPress,
showBottomBorder,
label,
}) => {
const renderIcon = () => {
if (!iconName) {
return null
if (iconName) {
return <Icon name={iconName} size={$size(28)} color={'#007AFF'} />
}
if (icon) {
return icon()
}
return <Icon name={iconName} size={$size(28)} color={'#007AFF'} />
}
return (
@ -33,7 +38,7 @@ export const ActionSheetButtonAtom: FC<IProps> = ({ @@ -33,7 +38,7 @@ export const ActionSheetButtonAtom: FC<IProps> = ({
{ borderBottomWidth: showBottomBorder ? 1 : 0 },
]}>
{renderIcon()}
<Txt style={styles.label} color="#FFFFFF" mod="md">
<Txt mod="lg" style={styles.label}>
{label}
</Txt>
</TouchableOpacity>
@ -44,9 +49,8 @@ const styles = StyleSheet.create({ @@ -44,9 +49,8 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#161616',
padding: $size(10),
borderBottomColor: 'rgba(212, 212, 212, 0.1)',
backgroundColor: colors.lightPurple,
padding: $size(15),
},
label: {
marginLeft: $size(10),

23
src/module/common/widgets/bottom-sheet/atoms/bottom-sheet-view.atom.tsx

@ -1,17 +1,18 @@ @@ -1,17 +1,18 @@
import React, { FC } from 'react'
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { StyleSheet, TouchableOpacity, View } from 'react-native'
import ActionSheet, { SheetProps } from 'react-native-actions-sheet'
import { Txt } from '~modules/common/components/typography'
import { SheetManager } from 'react-native-actions-sheet'
import { $size } from '~modules/common/helpers'
import { ActionSheetButtonAtom } from './action-sheet-button.atom'
import _ from 'lodash'
import { Txt } from '../../../components'
import { $size } from '../../../helpers'
import { ActionSheetButtonAtom } from './action-sheet-button.atom'
import { colors } from '../../../colors'
interface IPayloadSheet {
iconName?: string
iconName: string
onPress: () => void
label: string
icon?: () => React.ReactElement
}
export const BottomSheetView: FC<SheetProps<IPayloadSheet[]>> = ({
@ -28,13 +29,14 @@ export const BottomSheetView: FC<SheetProps<IPayloadSheet[]>> = ({ @@ -28,13 +29,14 @@ export const BottomSheetView: FC<SheetProps<IPayloadSheet[]>> = ({
statusBarTranslucent={true}
animated>
<View style={styles.actionContainer}>
{payload.map((it, index) => {
{payload?.map((it, index) => {
const showBottomBorder = payload.length - 1 !== index
return (
<ActionSheetButtonAtom
key={it.label}
icon={it?.icon}
onPress={it.onPress}
iconName={it.iconName}
iconName={it?.iconName}
label={it.label}
showBottomBorder={showBottomBorder}
/>
@ -55,11 +57,11 @@ const styles = StyleSheet.create({ @@ -55,11 +57,11 @@ const styles = StyleSheet.create({
paddingVertical: $size(18),
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#161616',
backgroundColor: colors.darkPurple,
borderRadius: 16,
},
container: {
backgroundColor: 'rgba(0,0,0,0.1)',
backgroundColor: colors.lightPurple,
paddingHorizontal: $size(12),
paddingBottom: $size(35),
},
@ -70,7 +72,6 @@ const styles = StyleSheet.create({ @@ -70,7 +72,6 @@ const styles = StyleSheet.create({
actionContainer: {
borderRadius: 16,
padding: $size(10),
backgroundColor: '#161616',
flexDirection: 'column',
marginBottom: $size(16),
},

1
src/module/common/widgets/bottom-sheet/atoms/index.ts

@ -1 +1,2 @@ @@ -1 +1,2 @@
export * from './bottom-sheet-view.atom'
export * from './action-sheet-button.atom'

1
src/module/common/widgets/bottom-sheet/index.ts

@ -0,0 +1 @@ @@ -0,0 +1 @@
export * from './sheets'

1
src/module/common/widgets/index.ts

@ -1,2 +1,3 @@ @@ -1,2 +1,3 @@
export * from './alert'
export * from './alert-confirm'
export * from './bottom-sheet'

2
src/module/game/screens/game.screen.tsx

@ -22,7 +22,7 @@ export const GameScreen: FC = () => { @@ -22,7 +22,7 @@ export const GameScreen: FC = () => {
const packageName = params.packageName
const goBack = () => {
nav.navigate(RouteKey.Package)
nav.navigate(RouteKey.Packages)
}
const randomGame = () => {

2
src/module/game/screens/questions.screen.tsx

@ -27,7 +27,7 @@ export const QuestionsScreen: React.FC = () => { @@ -27,7 +27,7 @@ export const QuestionsScreen: React.FC = () => {
}
const goGameScreen = () => {
nav.navigate(RouteKey.Package)
nav.navigate(RouteKey.Packages)
dispatch(nextStep())
}

2
src/module/packages/screens/packages-list.screen.tsx

@ -17,7 +17,7 @@ export const PackagesListScreen: FC = () => { @@ -17,7 +17,7 @@ export const PackagesListScreen: FC = () => {
headerComponent={
<Header
rightIcon="setting"
onPressRight={() => nav.navigate(RouteKey.Setting)}
onPressRight={() => nav.navigate(RouteKey.SettingsGroup)}
/>
}>
<View style={styles.container}>

2
src/module/root/atoms/on-boarding-button.component.tsx

@ -22,7 +22,7 @@ export const OnBoardingBottom: FC<IProps> = ({ isLastBlock, onPressSkip }) => { @@ -22,7 +22,7 @@ export const OnBoardingBottom: FC<IProps> = ({ isLastBlock, onPressSkip }) => {
const onBoardFinish = async () => {
await AsyncStorage.setItem(StorageKey.OnBoarding, 'true')
nav.navigate(RouteKey.Package)
nav.navigate(RouteKey.Packages)
}
return (

2
src/module/root/config/on-boarding.config.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import ImageHearts from '../../../assets/image/hearts.svg'
import ImageGlass from '../../../assets/image/glass.svg'
import ImageCup from '../../../assets/image/winners-cup.svg'
import { OnBoardingLocale } from '../../../i18n/types/on-boarding.types'
import { OnBoardingLocale } from '../../../i18n/interfaces/on-boarding.types.interface'
const translatePath = (
itemKey: keyof OnBoardingLocale.OnboardingSteps,

45
src/module/root/navigations-groups/user.group.tsx

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import React, { FC } from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { RouteKey } from '../../common'
import { RouteKey, SettingsKey } from '../../common'
import { GameScreen, QuestionsScreen } from '../../game'
import { PackagesListScreen } from '../../packages'
import {
@ -9,10 +9,16 @@ import { @@ -9,10 +9,16 @@ import {
SettingsScreen,
} from '../screens'
import { LoadingScreen } from '../screens/loading-screen'
import { PrivacyPolicyScreen } from '../../settings'
import {
PrivacyPolicyScreen,
PurchasesScreen,
WriteToUsScreen,
} from '../../settings'
const Stack = createNativeStackNavigator()
const SettingsStack = createNativeStackNavigator()
export const UserNavigationGroup: FC = () => {
return (
<Stack.Navigator
@ -26,7 +32,7 @@ export const UserNavigationGroup: FC = () => { @@ -26,7 +32,7 @@ export const UserNavigationGroup: FC = () => {
component={QuestionsScreen}
/>
<Stack.Screen
name={RouteKey.Package}
name={RouteKey.Packages}
component={PackagesListScreen}
/>
<Stack.Screen
@ -39,11 +45,38 @@ export const UserNavigationGroup: FC = () => { @@ -39,11 +45,38 @@ export const UserNavigationGroup: FC = () => {
component={LanguageSelectScreen}
/>
<Stack.Screen name={RouteKey.Game} component={GameScreen} />
<Stack.Screen name={RouteKey.Setting} component={SettingsScreen} />
<Stack.Screen
name={RouteKey.PrivacyPolicy}
component={PrivacyPolicyScreen}
name={RouteKey.SettingsGroup}
component={UserSettingsNavigationGroup}
/>
</Stack.Navigator>
)
}
const UserSettingsNavigationGroup = () => {
return (
<SettingsStack.Navigator
initialRouteName={SettingsKey.Settings}
screenOptions={{
headerShown: false,
animation: 'slide_from_left',
}}>
<SettingsStack.Screen
name={SettingsKey.Settings}
component={SettingsScreen}
/>
<Stack.Screen
name={SettingsKey.PrivacyPolicy}
component={PrivacyPolicyScreen}
/>
<Stack.Screen
name={SettingsKey.Purchases}
component={PurchasesScreen}
/>
<Stack.Screen
name={SettingsKey.WriteToUs}
component={WriteToUsScreen}
/>
</SettingsStack.Navigator>
)
}

2
src/module/root/screens/language-select.screen.tsx

@ -45,7 +45,7 @@ export const LanguageSelectScreen: FC = () => { @@ -45,7 +45,7 @@ export const LanguageSelectScreen: FC = () => {
}
return (
<ScreenLayout horizontalPadding={24}>
<ScreenLayout>
<View style={styles.container}>
<Txt style={styles.title}>Choose your language</Txt>
{languageList.map(el => (

2
src/module/root/screens/loading-screen.tsx

@ -39,7 +39,7 @@ export const LoadingScreen: FC = () => { @@ -39,7 +39,7 @@ export const LoadingScreen: FC = () => {
}
if (isOnBoard && language) {
nav.navigate(RouteKey.Package)
nav.navigate(RouteKey.Packages)
} else if (language && !isOnBoard) {
nav.navigate(RouteKey.Onboarding)
} else if (!language) {

3
src/module/settings/atoms/index.ts

@ -1 +1,2 @@ @@ -1 +1,2 @@
export * from './selected-language-in-settings.atom';
export * from './selected-language-in-settings.atom'
export * from './switch-notifications.atom'

40
src/module/settings/atoms/selected-language-in-settings.atom.tsx

@ -1,25 +1,21 @@ @@ -1,25 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import React from 'react'
import { StyleSheet } from 'react-native'
import { useTranslation } from 'react-i18next'
import { $size, Txt, colors } from '../../common'
export const SelectedLanguage = () => {
const {t, i18n} = useTranslation();
return (
<View style={styles.curentLang}>
<Text style={styles.text}>{i18n.language}</Text>
</View>
);
};
const { i18n } = useTranslation()
console.log(i18n.language)
return <Txt style={styles.text}>{i18n.language}</Txt>
}
const styles = StyleSheet.create({
curentLang: {
flex: 0,
alignSelf: 'center',
},
text: {
color: '#A798FF',
fontWeight: '600',
fontSize: 18,
lineHeight: 28,
textTransform: 'uppercase',
},
});
text: {
color: colors.purple,
fontWeight: '600',
fontSize: $size(18),
lineHeight: $size(28),
textTransform: 'uppercase',
},
})

22
src/module/settings/atoms/switch-notifications.atom.tsx

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
import React, { useState } from 'react'
import { Switch } from 'react-native'
import { $size, colors } from '../../common'
export const SwitchNotificationsAtom = () => {
const [isEnabled, setIsEnabled] = useState(false)
const toggleSwitch = () => {
setIsEnabled(previousState => !previousState)
}
return (
<Switch
trackColor={{ true: colors.purple }}
thumbColor={isEnabled ? colors.turquoise : colors.darkPurple}
ios_backgroundColor={colors.purple}
onValueChange={toggleSwitch}
style={{ width: $size(51) }}
value={isEnabled}
/>
)
}

30
src/module/settings/components/settings-item.component.tsx

@ -1,33 +1,26 @@ @@ -1,33 +1,26 @@
import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, View, TouchableOpacity } from 'react-native'
import { $size, Icon, RouteKey, Txt, colors, useNav } from '../../common'
import { $size, Icon, Txt, colors } from '../../common'
interface IProps {
title: string
iconName: string
component?: () => JSX.Element
onPressSettingItem: () => void
}
export const SettingsItem: FC<IProps> = ({ title, iconName, component }) => {
const { t } = useTranslation()
const nav = useNav()
const goTo = () => {
console.log(title)
switch (title) {
case 'settingTranslation.policy':
nav.navigate(RouteKey.PrivacyPolicy)
break
}
}
export const SettingsItem: FC<IProps> = ({
title,
iconName,
component,
onPressSettingItem,
}) => {
return (
<TouchableOpacity style={styles.container} onPress={goTo}>
<TouchableOpacity style={styles.container} onPress={onPressSettingItem}>
<View style={styles.row}>
<Icon name={iconName} size={$size(24)} color={colors.purple} />
<Txt mod="lg" style={styles.text}>
{t(title)}
{title}
</Txt>
</View>
{component && component()}
@ -41,14 +34,13 @@ const styles = StyleSheet.create({ @@ -41,14 +34,13 @@ const styles = StyleSheet.create({
},
text: {
color: colors.purple,
lineHeight: $size(24),
marginLeft: $size(10),
},
container: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: $size(24),
height: $size(24),
height: $size(28),
justifyContent: 'space-between',
},
})

13
src/module/settings/config/settings.config.tsx

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import React from 'react'
import { SelectedLanguage } from '../atoms/selected-language-in-settings.atom'
import { SettingLocale } from '../../../i18n/types/settings.types'
import { SettingLocale } from '../../../i18n/interfaces/settings.types.interface'
import { SelectedLanguage, SwitchNotificationsAtom } from '../atoms'
const translatePath = (itemKey: keyof SettingLocale.Core) =>
`settingTranslation.${itemKey}`
@ -15,6 +15,11 @@ export const settingsConfig = [ @@ -15,6 +15,11 @@ export const settingsConfig = [
image: 'lang',
component: () => <SelectedLanguage />,
},
{
title: translatePath('notifications'),
image: 'notification',
component: () => <SwitchNotificationsAtom />,
},
{
title: translatePath('write'),
image: 'message',
@ -31,8 +36,4 @@ export const settingsConfig = [ @@ -31,8 +36,4 @@ export const settingsConfig = [
title: translatePath('policy'),
image: 'privacy-policy',
},
{
title: translatePath('information'),
image: 'information',
},
]

1
src/module/settings/index.ts

@ -2,3 +2,4 @@ export * from './screens' @@ -2,3 +2,4 @@ export * from './screens'
export * from './atoms'
export * from './components'
export * from './config'
export * from './validator'

2
src/module/settings/screens/index.ts

@ -1,2 +1,4 @@ @@ -1,2 +1,4 @@
export * from './privacy-policy'
export * from './settings.screen'
export * from './purchases.screen'
export * from './write-to-us.screen'

43
src/module/settings/screens/purchases.screen.tsx

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, View } from 'react-native'
import {
$size,
ButtonPrimary,
colors,
Header,
ScreenLayout,
Txt,
useNav,
} from '../../common'
import { SheetManager } from 'react-native-actions-sheet'
export const PurchasesScreen: FC = () => {
const { t } = useTranslation()
const nav = useNav()
return (
<ScreenLayout
headerComponent={
<Header
leftIcon="arrow"
title={t('pageTitles.purchases')}
onPressLeft={() => nav.goBack()}
/>
}>
<View></View>
</ScreenLayout>
)
}
const styles = StyleSheet.create({
container: {
backgroundColor: colors.darkPurple,
borderRadius: 20,
padding: 20,
},
description: {
color: colors.purple,
lineHeight: $size(30),
},
})

90
src/module/settings/screens/settings.screen.tsx

@ -1,13 +1,88 @@ @@ -1,13 +1,88 @@
import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { Share, View } from 'react-native'
import { SettingsItem } from '../components/settings-item.component'
import { settingsConfig } from '../config/settings.config'
import { Header, colors, ScreenLayout, useNav } from '../../common'
import {
Header,
Language,
ScreenLayout,
SettingsKey,
useNav,
} from '../../common'
import { SheetManager } from 'react-native-actions-sheet'
import UALogo from '../../../assets/icons/UKR.svg'
import UAELogo from '../../../assets/icons/UAE.svg'
import ENGLogo from '../../../assets/icons/ENG.svg'
export const SettingsScreen: FC = () => {
const { t, i18n } = useTranslation()
const nav = useNav()
const { t } = useTranslation()
const configActions = [
{
icon: () => <ENGLogo />,
onPress: () => onChangeLanguage(Language.EN),
label: 'English',
},
{
icon: () => <UALogo />,
onPress: () => onChangeLanguage(Language.UA),
label: 'Українська',
},
// {
// icon: () => <UAELogo />,
// onPress: () => onChangeLanguage(Language.HI),
// label: 'Hindi',
// },
]
const shareApp = async () => {
try {
const shareOptions = {
message: 'Share this cool app with your friends',
}
await Share.share(shareOptions)
} catch (error) {
console.log(error)
}
}
const onChangeLanguage = (language: Language) => {
SheetManager.hide('bottom-sheet')
return i18n.changeLanguage(language)
}
const openBottomSheetForChangeLanguage = () => {
SheetManager.show('bottom-sheet', {
payload: configActions,
})
}
const onPressSettingItem = (key: string) => {
switch (key) {
case 'purchases':
nav.navigate(SettingsKey.Purchases)
break
case 'lang':
openBottomSheetForChangeLanguage()
break
case 'notification':
break
case 'message':
nav.navigate(SettingsKey.WriteToUs)
break
case 'privacy-policy':
nav.navigate(SettingsKey.PrivacyPolicy)
break
case 'rate':
break
case 'share':
shareApp()
break
}
}
return (
<ScreenLayout
@ -18,16 +93,19 @@ export const SettingsScreen: FC = () => { @@ -18,16 +93,19 @@ export const SettingsScreen: FC = () => {
onPressLeft={() => nav.goBack()}
/>
}>
<View>
<>
{settingsConfig.map((item, index) => (
<SettingsItem
key={index}
title={item.title}
title={t(item.title)}
iconName={item.image}
component={item.component}
onPressSettingItem={() =>
onPressSettingItem(item.image)
}
/>
))}
</View>
</>
</ScreenLayout>
)
}

67
src/module/settings/screens/write-to-us.screen.tsx

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet } from 'react-native'
import {
$size,
appEvents,
ButtonPrimary,
colors,
FormTextControll,
Header,
ScreenLayout,
useForm,
useNav,
} from '../../common'
import { writeToUsValidator } from '../validator'
interface WriteUsForm {
message: string
}
export const WriteToUsScreen: FC = () => {
const { t } = useTranslation()
const nav = useNav()
const form = useForm<WriteUsForm>({}, writeToUsValidator)
const onSendText = () => {
appEvents.emit('alert', {
title: 'Aga, thanks',
subtitle: 'We rozberemosya',
onClose: () => nav.goBack(),
})
}
return (
<ScreenLayout
bottomSafeArea
headerComponent={
<Header
leftIcon="arrow"
title={t('pageTitles.writeToUs')}
onPressLeft={() => nav.goBack()}
/>
}>
<FormTextControll
label={t('settingTranslation.label')}
value={form.values.message}
onChange={val => form.setFormField('message', val)}
inputProps={{ multiline: true }}
inputStyle={{ height: $size(100) }}
error={form.errors['message']}
/>
<ButtonPrimary
style={styles.button}
disabled={!form.values.message}
onPress={() => form.onSubmit(onSendText)}>
Send to us
</ButtonPrimary>
</ScreenLayout>
)
}
const styles = StyleSheet.create({
button: {
marginTop: $size(20),
backgroundColor: colors.lightPurple,
},
})

1
src/module/settings/validator/index.ts

@ -0,0 +1 @@ @@ -0,0 +1 @@
export * from './writeToUs.validator'

15
src/module/settings/validator/writeToUs.validator.ts

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
import validate from 'validate.js'
import { presenceCost } from '../../common'
const constraints = {
message: {
presence: presenceCost,
length: {
minimum: 5,
},
},
}
export const writeToUsValidator = (data: any) => {
return validate(data, constraints)
}
Loading…
Cancel
Save