This repository contains the frontend codebase for an easy to use, pet friendly, care services application called Rufferal. The application is built using React Native and is designed to be responsive across multiple platforms including Android and iOS (coming soon: desktop & mobile-web).
- Demo
- Features
- Accessibility considerations
- Extensions
- Design
- Software architecture
- Installation
- About the creators
[ video ]
[ desktop screengrab ]
[ mobile web screengrab ]
[ android screengrab ]
[ ios screengrab ]
- Cross-platform Compatibility: Supports desktop browsers, mobile web browsers, Android devices, and iOS devices.
- Easy Onboarding and Research Caretakers: Pet owners can skip sign in and directly browse services before signing up.
- User Authentication: Secure user authentication and authorization flows with phone number, email, and social sign on.
- Community Referrals: Pet owners can provide referrals (Ruffrls) to give insight into their experience with Caretakers and pet owners can see referral details while searching.
- Build or View Pet Profiles: Fill out pet profiles to provide details about pet care as well as
- Gain Trust: Caretakers can show off their qualifications via friendly and fun icons as well as set transparent prices.
- Book Care for Your Pet: Pet owners can book various pet care services.
- Book Gigs: Caretakers can browse available services by Pet and see
- Switch Modes: Easily switch between Pet owner or Caretaker to book gigs or book services.
- Payment Integration: Integration with a secure payment gateway for handling transactions.
- Profile Management: Users can manage their profiles and pet information.
[ axe and other services screenshots, or walkthrough, or whatever evidence we can produce here]
[ details/list ]
- IOS (versions coming soon and above)
- Android (versions coming soon and above)
- mobile-web and desktop coming soon
- Notifications: Push notifications for appointment and payment reminders, messaging notifications, and updates.
- Internal Messaging: 1:1 messaging between Pet owners and caretakers to communicate details, discuss payment, receive updates about their pets, and so much more.
- AI Powered Care Plans: Pet Owners can use our AI powered assistant, Ruffles, to create caretaker friendly care plan to attach to their pet's profile that can include walking details, overnight details, elderly pet details, pet medical details, and more
- Details about Ruffles
- Ruffles would be a charming and distinctive companion, known for their unique fluffy coat and friendly demeanor. They would capture hearts with their adorable appearance and playful personality, making them a cherished member of any household.
- Physical Characteristics:
- Breed: A mixed breed with a uniquely fluffy and slightly unkempt appearance, possibly a combination of breeds like a Shih Tzu and Pomeranian mix.
- Size: Small to medium-sized, compact but with a fluffy and slightly tousled coat.
- Coat: Soft and voluminous, resembling the texture of wind-blown fur, with slight waves or curls.
- Color: Varied shades of cream and light brown, with patches or streaks of darker colors adding to their distinctive look.
- Facial Features:
- Eyes: Round and expressive, often dark brown or amber in color, conveying curiosity and intelligence.
- Ears: Medium-sized and covered with tufts of fur, often perking up at the slightest sound or movement.
- Expression: Sweet and endearing, with a hint of mischievousness in their gaze.
- Personality Traits:
- Cheerful: Always wearing a bright, happy expression, eager to explore and engage in playful activities.
- Affectionate: Loves cuddling and being close to their human family members, seeking attention and affection.
- Energetic: Despite their fluffy appearance, Ruffles is surprisingly agile and enjoys running around and playing fetch.
- Intelligent: Quick to learn new tricks and commands, showing off their cleverness and eagerness to please.
- graphql
- error handling
- security handling
- unit testing
- integration testing
- e2e testing
- deployment
- env vars and secrets
- deployment
- other developer nice to haves
more coming soon
CURRENT SETUP tailwind/src/tailwind.config.js
import { moderateScale } from '@rufferal/utils';
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [],
theme: {
extend: {
colors: {
blizzardBlue: {
50: '#ECFDFF',
100: '#CEF8FF',
200: '#A0EFFE', // PRIMARY
300: '#64E2FC',
400: '#1DCBF3',
500: '#01ADD9',
600: '#0489B6',
700: '#0B6E93',
800: '#135977',
900: '#144A65',
950: '#073145',
},
whitePointer: {
50: '#FDF9FF', // PRIMARY
100: '#F7E8FF',
200: '#F0D5FF',
300: '#E4B4FE',
400: '#D484FC',
500: '#C355F7',
600: '#B233EA',
700: '#9B22CE',
800: '#8221A8',
900: '#6A1C87',
950: '#4B0764',
},
balticSea: {
50: '#F6F4F9',
100: '#EFEBF4',
200: '#E2DBEA',
300: '#D0C5DC',
400: '#BEADCC',
500: '#AF98BC',
600: '#9D81AA',
700: '#896E94',
800: '#6E5B78',
900: '#5B4D62',
950: '#2B242E', // PRIMARY
},
electricViolet: {
50: '#FBF5FF',
100: '#F6E8FF',
200: '#EFD6FE',
300: '#E2B5FD',
400: '#D086FA',
500: '#BE58F4',
600: '#AC36E7',
700: '#9525CB', // PRIMARY
800: '#7D23A6',
900: '#661E85',
950: '#470962',
},
seance: {
50: '#FBF5FF',
100: '#F6E9FE',
200: '#EFD6FE',
300: '#E2B6FC',
400: '#D087F9',
500: '#BE59F3',
600: '#AC37E6',
700: '#9526CA',
800: '#7D24A5', // PRIMARY
900: '#671E85',
950: '#480962',
},
wildSand: {
50: '#F6F6F6', // PRIMARY
100: '#EFEFEF',
200: '#DCDCDC',
300: '#BDBDBD',
400: '#989898',
500: '#7C7C7C',
600: '#656565',
700: '#525252',
800: '#464646',
900: '#3D3D3D',
950: '#292929',
},
iron: {
50: '#F7F7F7',
100: '#EDEDED',
200: '#D8D8D8', // DISABLED
300: '#D1D1D1', // PRIMARY
400: '#ADADAD',
500: '#999999', // DISABLED
600: '#888888',
700: '#7B7B7B',
800: '#676767',
900: '#545454',
950: '#363636',
},
graySuit: {
50: '#F9F8FA',
100: '#F4F2F5',
200: '#E9E8EC',
300: '#D8D5DD',
400: '#CAC4D0', // PRIMARY
500: '#AA9FB3',
600: '#97889F',
700: '#83768B',
800: '#6E6275',
900: '#5A5260',
950: '#3C3540',
},
saltBox: {
50: '#FAF9FA',
100: '#F3F2F5',
200: '#E8E4EA',
300: '#D4CED9',
400: '#BBB1C1',
500: '#9E90A5',
600: '#807188',
700: '#695C6F', // PRIMARY
800: '#564C5C',
900: '#4A424D',
950: '#2B242E',
},
lola: {
50: '#F9F8FA',
100: '#F4F2F5',
200: '#EBE7ED',
300: '#D5CED9', // PRIMARY
400: '#C5BBCA',
500: '#AE9FB3',
600: '#9A889F',
700: '#88758C',
800: '#716275',
900: '#5E5161',
950: '#3E3540',
},
red: {
50: '#fff3f1',
100: '#ffe3df',
200: '#ffcbc4',
300: '#ffa69b',
400: '#ff7462',
500: '#ff4931',
600: '#e8270e', // PRIMARY
700: '#cb200a',
800: '#a71f0d',
900: '#8a2012',
950: '#4c0b03',
},
silver: {
50: '#F7F7F7',
100: '#EDEDED',
200: '#DFDFDF',
300: '#C9C9C9', // PRIMARY
400: '#ADADAD',
500: '#999999',
600: '#888888',
700: '#7B7B7B',
800: '#676767',
900: '#545454',
950: '#363636',
},
codGray: {
50: '#F6F6F6',
100: '#E7E7E7',
200: '#D1D1D1',
300: '#B0B0B0',
400: '#888888',
500: '#6D6D6D',
600: '#5D5D5D',
700: '#4F4F4F',
800: '#454545',
900: '#3D3D3D',
950: '#080808', // PRIMARY
},
amethystSmoke: {
50: '#F9F8FA',
100: '#F4F2F5',
200: '#EAE7ED',
300: '#D9D4DE',
400: '#C3BCC9',
500: '#AC9FB3',
600: '#9F90A5', // PRIMARY
700: '#86758C',
800: '#706275',
900: '#5D5161',
950: '#3D3540',
},
azureRadiance: {
100: '#D6F2FF',
200: '#B5EAFF',
300: '#83DFFF',
400: '#48CBFF',
50: '#EDFAFF',
500: '#1EACFF',
600: '#068EFF',
700: '#007AFF', // PRIMARY
800: '#085DC5',
900: '#0D519B',
950: '#0E315D',
},
chatelle: {
50: '#FAF8FA',
100: '#F4F2F5',
200: '#EAE8EC',
300: '#D9D5DD',
400: '#BCB1C1', // PRIMARY
500: '#AE9FB3',
600: '#9B889F',
700: '#88758C',
800: '#716275',
900: '#5D5260',
950: '#3E3540',
},
},
fontFamily: {
body: ['Inter Regular'], // 400
bodyItalic: ['Inter Regular Italic'],
bodyMedium: ['Inter Medium'], // 500
bodySemibold: ['Inter Semibold'], // 600
bodyBold: ['Inter Bold'], // 700
headerSemibold: ['Proxima Nova Semibold'], // 600
headerBold: ['Proxima Nova Bold'], // 700
headerExtrabold: ['Proxima Nova Extrabold'], // 800
},
fontSize: {
b1: [`${moderateScale(10)}px`, `${moderateScale(14)}px`],
b2: [`${moderateScale(12)}px`, `${moderateScale(16)}px`],
b3: [`${moderateScale(14)}px`, `${moderateScale(20)}px`],
b4: [`${moderateScale(16)}px`, `${moderateScale(24)}px`],
h3: [`${moderateScale(22)}px`, `${moderateScale(26)}px`],
h2: [`${moderateScale(28)}px`, `${moderateScale(30)}px`],
h1: [`${moderateScale(32)}px`, `${moderateScale(36)}px`],
},
},
},
plugins: [],
};
- Designed for mobile displays from 320×568 through 430×1004
- Primary test devices
- ANDROID
- Galaxy S8
- 360 x 740
- IOS
- iPhone X
- 375 x 812
- ANDROID
- Smallest test devices
- ANDROID
- Galaxy S7
- 360 x 640
- IOS
- iPhone 5/SE
- 320 x 568
- ANDROID
- Largest test devices
- ANDROID
- Galaxy Z Flip 5
- 412 x 1004
- IOS
- iPhone 15 Pro Max
- 430 x 932
- ANDROID
coming soon
coming soon
[ diagram goes here ]
See backend
- React: JavaScript library for building user interfaces.
- React Native: Framework for building native applications using React.
- TypeScript: Strict syntactical superset of JavaScript.
- MobX: State management library for React applications.
- Styled Components: CSS-in-JS styling solution.
- EXTENSION: Tailwind refactor
- React Navigation: Routing and navigation for React Native applications.
- Axios: Promise-based HTTP client for making API requests.
- EXTENSION Apollo Client: A JavaScript library that helps manage data with GraphQL, both locally and remotely.
To get a local copy of the project up and running follow these steps:
- Repo/organization permissions
- Node
- npm
- Android Studio
- virtual device setup
- XCode
- simulator setup
-
Clone the repository:
git clone https://github.com/Ruffrl/rufferal-frontend.git cd rufferal-frontend
-
Install dependencies:
npm install
-
Mobile (React Native on Expo):
Ensure you have set up the development environment based on your target platform (iOS or Android).
- https://reactnative.dev/docs/environment-setup
- https://docs.expo.dev/get-started/set-up-your-environment/?mode=development-build
npx nx run rufferal:start
Follow in-server instructions to open android
a
or iosi
Simulators should open automatically, they may take a minute to load and bundleOPTIONALLY
npx nx run rufferal:run-android # For Android npx nx run rufferal:run-ios # For iOS
- Troubleshooting? - Sometimes you need to open Android Studio -> Virtual Devices -> Select and run a device
Future
- Fullstack server? - Debugging servers?
-
Web (Expo web):
npx nx run rufferal:start
Follow in-server instructions to open on web (w) OR Open http://localhost:3000 in your browser.
-
Mobile (React Native): coming soon
- https://nx.dev/nx-api/expo/executors/build
- https://nx.dev/reference/project-configuration#targets
- https://blog.nrwl.io/step-by-step-guide-to-creating-an-expo-monorepo-with-nx-30c976fdc2c1
- https://medium.com/@arkadi.berikashvili/react-native-eas-builds-on-nx-nrwl-expo-using-github-workflows-80f420f52563
-
Web: coming soon
-
Create a new NX app with expo
npx create-nx-workspace@latest --preset=expo --appName=rufferal ✔ Where would you like to create your workspace? · rufferal-frontend ✔ Test runner to use for end to end (E2E) tests · cypress ✔ Which CI provider would you like to use? · github
-
Create libraries
# UI LIBRARY npx nx generate @nx/expo:lib ui # I added my personal UI setup that follows "Atomic Design" methodologies # ASSETS npx nx generate @nx/expo:lib assets # STORE (currently MobX) npx nx generate @nx/expo:lib store # UTILS npx nx generate @nx/expo:lib utils # STYLES CONFIGURATION (currently Tailwind) npx nx generate @nx/expo:lib tailwind # Chose to use explicit naming instead of generic naming because most of the work in this library will be unique to Tailwind configuration # For custom tailwind configurations and branding/theme alignment
-
Name libraries accordingly
In
tsconfig.base.json
:{ ... "paths": { "@rufferal/assets/*": ["assets/*"], "@rufferal/store": ["store/src/index.ts"], "@rufferal/tailwind": ["tailwind/src/index.ts"], "@rufferal/ui": ["ui/src/index.ts"], "@rufferal/utils": ["utils/src/index.ts"] } }
-
Generate components
nx g @nx/expo:component bottomsheet --directory ui/src/components/atoms/bottomsheet --nameAndDirectoryFormat=as-provided --export=false # Updates # - Convert component to arrow component without a default export # - Export component from directory # - `ui/src/components/atoms/index.ts` # - `export { Bottomsheet } from './bottomsheet/bottomsheet';` # - `ui/src/components/index.ts` # - `export * from './atoms';` # - `ui/src/index.ts` # - `export * from './components';`
Personally, I ended up not using the component generator as it currently is
- I would like to setup a component generator that applies my system/library expectations
- Creates functional (arrow) components instead of default exported normal function componets
- exports to local component folder (if in atoms, export is in ./atoms/index.ts, etc)
- I would like to setup a component generator that applies my system/library expectations
-
Manage expo assets and update config accordingly
-
apps/rufferal/app.json
{ ... "plugins": [ [ "expo-image-picker", { "photosPermission": "Allow Rufferal to access your photos" } ], [ "expo-camera", { "cameraPermission": "Allow Rufferal to access your camera", "microphonePermission": "Allow Rufferal to access your microphone", "recordAudioAndroid": true } ], [ "expo-asset", { "assets": ["../../lib/assets/images"] } ], [ "expo-font", { "fonts": [ "../../assets/src/fonts/proxima-nova/proximanova_bold.otf", "../../assets/src/fonts/proxima-nova/proximanova_extrabold.otf", "../../assets/src/fonts/proxima-nova/proximanova_semibold.otf", "../../assets/src/fonts/inter/inter_bold.otf", "../../assets/src/fonts/inter/inter_regular_italic.otf", "../../assets/src/fonts/inter/inter_regular.otf", "../../assets/src/fonts/inter/inter_semibold.otf", "../../assets/src/fonts/inter/inter_medium.otf" ] } ] ] }
-
Manage custom styles
- Meet the designer: Sara Flores
- Meet the developer: Priya Power
This project is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE - see the LICENSE file for details.
- Hat tip to anyone whose code was used
- Inspiration
- etc.