From d1a686caf6e3b05f5e13fc27c8f6a3080a5e3af9 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Sun, 26 Jul 2026 19:43:04 +0200 Subject: [PATCH] Replace react-native-ui-lib with homegrown components --- jest.setup.js | 10 - package-lock.json | 217 +--------------------- package.json | 1 - src/App.tsx | 3 - src/components/Button.tsx | 57 ++++++ src/components/FormInput.tsx | 2 +- src/components/TextField.tsx | 31 ++++ src/components/Toast.tsx | 78 ++++++++ src/modules/about/About.tsx | 2 +- src/modules/events/EventList.tsx | 2 +- src/modules/login/Login.tsx | 3 +- src/modules/membership/MembershipInfo.tsx | 2 +- src/modules/membership/Proof.tsx | 5 +- src/modules/membership/UserDelete.tsx | 2 +- src/modules/register/UserRegister.tsx | 5 +- src/theme.ts | 9 +- 16 files changed, 182 insertions(+), 247 deletions(-) create mode 100644 src/components/Button.tsx create mode 100644 src/components/TextField.tsx create mode 100644 src/components/Toast.tsx diff --git a/jest.setup.js b/jest.setup.js index 76d82d6..c07085a 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -14,16 +14,6 @@ global.fetch = jest.fn(async () => ({ json: async () => ({ events: [] }), })); -// react-native-ui-lib calls StatusBarManager.getHeight at import time, -// which the react-native jest mock does not provide. -const { NativeModules } = require('react-native'); - -NativeModules.StatusBarManager = { - HEIGHT: 42, - ...NativeModules.StatusBarManager, - getHeight: (callback) => callback({ height: 42 }), -}; - jest.mock('@react-native-async-storage/async-storage', () => require('@react-native-async-storage/async-storage/jest/async-storage-mock'), ); diff --git a/package-lock.json b/package-lock.json index 0b28f44..2347c17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,6 @@ "react-native-simple-radio-button": "^2.7.4", "react-native-svg": "15.15.3", "react-native-svg-transformer": "^1.5.3", - "react-native-ui-lib": "^7.26.2", "react-native-worklets": "0.7.4", "react-redux": "^9.2.0", "redux": "^5.0.1", @@ -3354,12 +3353,6 @@ "node": ">= 20.19.4" } }, - "node_modules/@react-native/normalize-color": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz", - "integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==", - "license": "MIT" - }, "node_modules/@react-native/normalize-colors": { "version": "0.83.6", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.83.6.tgz", @@ -5011,12 +5004,6 @@ "node": ">=6.5" } }, - "node_modules/abs-svg-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", - "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", - "license": "MIT" - }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -5613,12 +5600,6 @@ "@babel/plugin-syntax-flow": "^7.12.1" } }, - "node_modules/babel-plugin-transform-inline-environment-variables": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-environment-variables/-/babel-plugin-transform-inline-environment-variables-0.0.2.tgz", - "integrity": "sha512-8gobU7uuTIjz62aXTEZOH5yhuIPojNVAgLK0xnepdGS19aqOEphy7FVWBsojPa14yrQGM/w63uDox4thYcHCnA==", - "license": "MIT" - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", @@ -6145,16 +6126,6 @@ "node": ">= 10" } }, - "node_modules/commons-validator-js": { - "version": "1.0.1669", - "resolved": "https://registry.npmjs.org/commons-validator-js/-/commons-validator-js-1.0.1669.tgz", - "integrity": "sha512-T6rxAirPJuBpf9oPvn+ayNgGMAgaLcvDLfP1kzyMKpp+5AK2ARczHQK/r80SKRnR6fP6ElXOWGtH4zeAJ9DjmQ==", - "license": "Apache-2.0", - "dependencies": { - "lodash.includes": "^4.3.0", - "punycode": "^1.4.1" - } - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -6517,22 +6488,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -6673,17 +6628,6 @@ "node": ">= 0.8" } }, - "node_modules/deprecated-react-native-prop-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz", - "integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==", - "license": "MIT", - "dependencies": { - "@react-native/normalize-color": "*", - "invariant": "*", - "prop-types": "*" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -12295,6 +12239,7 @@ "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, "license": "MIT" }, "node_modules/lodash.debounce": { @@ -12303,12 +12248,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -13186,15 +13125,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-svg-path": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", - "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", - "license": "MIT", - "dependencies": { - "svg-arc-to-cubic-bezier": "^3.0.0" - } - }, "node_modules/npm-package-arg": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", @@ -13697,12 +13627,6 @@ "node": ">=10" } }, - "node_modules/parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", - "license": "MIT" - }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -14138,12 +14062,6 @@ "node": ">=6" } }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "license": "MIT" - }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -14183,6 +14101,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, "license": "MIT" }, "node_modules/queue": { @@ -14440,33 +14359,6 @@ "node": ">=10" } }, - "node_modules/react-native-redash": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/react-native-redash/-/react-native-redash-12.6.1.tgz", - "integrity": "sha512-SChHzssVr512PfZxGCcVMmlAzQ20k5BkC8BiSfZls6bFohLiJT3ih6Of9mPmaTENCQWe7ywTx7gzr3tAnIu2mg==", - "license": "MIT", - "dependencies": { - "abs-svg-path": "^0.1.1", - "normalize-svg-path": "^1.0.1", - "parse-svg-path": "^0.1.2", - "use-memo-one": "^1.1.1" - }, - "peerDependencies": { - "react": "*", - "react-native": "*", - "react-native-gesture-handler": "*", - "react-native-reanimated": "*" - } - }, - "node_modules/react-native-redash/node_modules/use-memo-one": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", - "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-native-safe-area-context": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz", @@ -14528,74 +14420,6 @@ "react-native-svg": ">=12.0.0" } }, - "node_modules/react-native-ui-lib": { - "version": "7.46.3", - "resolved": "https://registry.npmjs.org/react-native-ui-lib/-/react-native-ui-lib-7.46.3.tgz", - "integrity": "sha512-oE564MpcQNTYLsGN/9YgTt2Cr6NlJUs8a71trZr2AyRTeSMN8OjGOAnos+SuKL65VW9BYwYNw5iKViwhjfcWLw==", - "license": "MIT", - "dependencies": { - "babel-plugin-transform-inline-environment-variables": "^0.0.2", - "color": "^3.1.0", - "commons-validator-js": "^1.0.237", - "date-fns": "^2.29.3", - "deprecated-react-native-prop-types": "^2.3.0", - "hoist-non-react-statics": "^3.0.0", - "lodash": "^4.17.21", - "memoize-one": "^5.0.5", - "prop-types": "^15.5.10", - "react-freeze": "^1.0.0", - "react-native-redash": "^12.0.3", - "semver": "^5.5.0", - "tinycolor2": "^1.4.2", - "uilib-native": "4.5.1", - "url-parse": "^1.2.0", - "wix-react-native-text-size": "1.0.9" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": ">=17.0.1", - "react-native": ">=0.64.1", - "react-native-gesture-handler": ">=2.5.0", - "react-native-reanimated": ">=2.0.0", - "react-native-ui-lib": "*" - } - }, - "node_modules/react-native-ui-lib/node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/react-native-ui-lib/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/react-native-ui-lib/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/react-native-ui-lib/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/react-native-worklets": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.7.4.tgz", @@ -14990,6 +14814,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, "license": "MIT" }, "node_modules/resolve": { @@ -16107,12 +15932,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svg-arc-to-cubic-bezier": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", - "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==", - "license": "ISC" - }, "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -16315,12 +16134,6 @@ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "license": "MIT" }, - "node_modules/tinycolor2": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -16668,20 +16481,6 @@ "node": ">=14.17" } }, - "node_modules/uilib-native": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/uilib-native/-/uilib-native-4.5.1.tgz", - "integrity": "sha512-hcs4RSIqFqO9b2yLzvcVzj85XmC3WOR16dyUOh4RAcOoNpTMf0f2Tc4MazNLCeU8B/UO8WyVOcr2NvSHaiU6KQ==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.21", - "prop-types": "^15.5.10" - }, - "peerDependencies": { - "react": ">=17.0.1", - "react-native": ">=0.64.1" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -16858,6 +16657,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, "license": "MIT", "dependencies": { "querystringify": "^2.1.1", @@ -17141,15 +16941,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wix-react-native-text-size": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/wix-react-native-text-size/-/wix-react-native-text-size-1.0.9.tgz", - "integrity": "sha512-ymqEt4cfOQisFU/aTrDLvu5iVCcoSo+brlA4mwVHNtq8cpKGNRKBDsMMzFApGkUmQ6tJSDhzm5QHXv+3aE6tqw==", - "license": "BSD-2-Clause", - "peerDependencies": { - "react-native": ">=0.59.0" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index dfa86ca..e388506 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "react-native-simple-radio-button": "^2.7.4", "react-native-svg": "15.15.3", "react-native-svg-transformer": "^1.5.3", - "react-native-ui-lib": "^7.26.2", "react-native-worklets": "0.7.4", "react-redux": "^9.2.0", "redux": "^5.0.1", diff --git a/src/App.tsx b/src/App.tsx index 8762607..9568e7a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,6 @@ import 'expo-dev-client'; import AppInner from './AppInner'; import { useDeepLinking } from './hooks'; import { store, persistor } from './reduxStore'; -import { loadTheme } from './theme'; // Configure notifications Notifications.setNotificationHandler({ @@ -28,8 +27,6 @@ const apolloClient = new ApolloClient({ cache: new InMemoryCache(), }); -loadTheme(); - export default function App() { useDeepLinking(); return ( diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..f02ea58 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { Pressable, PressableProps, StyleProp, StyleSheet, ViewStyle } from 'react-native'; + +import theme from 'src/theme'; + +export type ButtonProps = Omit & { + style?: StyleProp; + fullWidth?: boolean; + small?: boolean; + children?: React.ReactNode; +}; + +const Button = ({ style, fullWidth, small, disabled, children, ...rest }: ButtonProps) => ( + [ + styles.base, + small && styles.small, + fullWidth && styles.fullWidth, + style, + pressed && styles.pressed, + disabled && styles.disabled, + ]} + {...rest} + > + {children} + +); + +const styles = StyleSheet.create({ + base: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 12, + paddingHorizontal: 20, + borderRadius: 24, + backgroundColor: theme.colors.neufBeige, + }, + small: { + paddingVertical: 6, + paddingHorizontal: 14, + borderRadius: 20, + }, + fullWidth: { + alignSelf: 'stretch', + }, + pressed: { + opacity: 0.7, + }, + disabled: { + opacity: 0.6, + }, +}); + +export default Button; diff --git a/src/components/FormInput.tsx b/src/components/FormInput.tsx index a49e2f7..f85072d 100644 --- a/src/components/FormInput.tsx +++ b/src/components/FormInput.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { Controller, UseControllerProps } from 'react-hook-form'; import { ReturnKeyTypeOptions, Text, StyleSheet } from 'react-native'; -import { TextField, TextFieldProps } from 'react-native-ui-lib'; +import TextField, { TextFieldProps } from 'src/components/TextField'; import theme from 'src/theme'; type FormInputProps = { diff --git a/src/components/TextField.tsx b/src/components/TextField.tsx new file mode 100644 index 0000000..1ace19f --- /dev/null +++ b/src/components/TextField.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { StyleProp, StyleSheet, Text, TextInput, TextInputProps, TextStyle, View, ViewStyle } from 'react-native'; + +export type TextFieldProps = TextInputProps & { + label?: React.ReactNode; + fieldStyle?: StyleProp; +}; + +const TextField = React.forwardRef(({ label, fieldStyle, style, ...rest }, ref) => ( + + {label != null && + (typeof label === 'string' || typeof label === 'number' ? {label} : label)} + + +)); + +TextField.displayName = 'TextField'; + +const styles = StyleSheet.create({ + container: { + marginVertical: 4, + }, + label: { + marginBottom: 2, + }, + input: { + fontSize: 16, + }, +}); + +export default TextField; diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx new file mode 100644 index 0000000..d1edf59 --- /dev/null +++ b/src/components/Toast.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Animated, StyleSheet, Text } from 'react-native'; + +import theme from 'src/theme'; + +export type ToastProps = { + message?: string; + visible?: boolean; + position?: 'top' | 'bottom'; + autoDismiss?: number; + onDismiss?: () => void; +}; + +const Toast = ({ message, visible, position = 'bottom', autoDismiss, onDismiss }: ToastProps) => { + const [mounted, setMounted] = useState(!!visible); + const opacity = useRef(new Animated.Value(0)).current; + + useEffect(() => { + let timer: ReturnType | undefined; + if (visible) { + setMounted(true); + Animated.timing(opacity, { toValue: 1, duration: 200, useNativeDriver: true }).start(); + if (autoDismiss && onDismiss) { + timer = setTimeout(onDismiss, autoDismiss); + } + } else { + Animated.timing(opacity, { toValue: 0, duration: 200, useNativeDriver: true }).start(({ finished }) => { + if (finished) { + setMounted(false); + } + }); + } + return () => { + if (timer) { + clearTimeout(timer); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [visible, autoDismiss]); + + if (!mounted) { + return null; + } + + return ( + + {message} + + ); +}; + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + left: 16, + right: 16, + backgroundColor: theme.colors.neufBlack, + borderRadius: 8, + paddingVertical: 12, + paddingHorizontal: 16, + }, + top: { + top: 48, + }, + bottom: { + bottom: 48, + }, + message: { + color: theme.colors.neufWhite, + textAlign: 'center', + fontSize: 15, + }, +}); + +export default Toast; diff --git a/src/modules/about/About.tsx b/src/modules/about/About.tsx index aa21809..71894fe 100644 --- a/src/modules/about/About.tsx +++ b/src/modules/about/About.tsx @@ -10,7 +10,6 @@ import { ScrollView, Dimensions, } from 'react-native'; -import { Button } from 'react-native-ui-lib'; import logo from 'assets/DNS-logo-svart.png'; import IconClock from 'assets/icons/clock.svg'; @@ -20,6 +19,7 @@ import IconMail from 'assets/icons/mail.svg'; import IconMap from 'assets/icons/map.svg'; import IconPhone from 'assets/icons/phone.svg'; import IconTiktok from 'assets/icons/tiktok.svg'; +import Button from 'src/components/Button'; import theme from 'src/theme'; const CHATEAU_NEUF_ADDRESS = 'Det Norske Studentersamfund, Slemdalsveien 15, 0369 Oslo'; diff --git a/src/modules/events/EventList.tsx b/src/modules/events/EventList.tsx index 895d8e0..04b2a4d 100644 --- a/src/modules/events/EventList.tsx +++ b/src/modules/events/EventList.tsx @@ -2,9 +2,9 @@ import { SimpleLineIcons as Icon } from '@expo/vector-icons'; import moment from 'moment'; import React from 'react'; import { StyleSheet, View, Platform, FlatList, TouchableOpacity, Text, Linking } from 'react-native'; -import { Button } from 'react-native-ui-lib'; import 'moment/locale/nb'; +import Button from 'src/components/Button'; import theme from 'src/theme'; import { EventType } from 'src/types/data'; diff --git a/src/modules/login/Login.tsx b/src/modules/login/Login.tsx index 9968453..d5b4115 100644 --- a/src/modules/login/Login.tsx +++ b/src/modules/login/Login.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { ActivityIndicator, Linking, StyleSheet, View, Text, ScrollView } from 'react-native'; -import { Button } from 'react-native-ui-lib'; +import Button from 'src/components/Button'; import FormErrors from 'src/components/FormErrors'; import FormInput from 'src/components/FormInput'; import theme from 'src/theme'; @@ -46,7 +46,6 @@ const Login = () => { {isLoggingIn && }