Skip to content

Commit

Permalink
feat(React InstantSearch Native Hooks): add Getting Started example (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahdayan committed Feb 10, 2022
1 parent 9708021 commit 71710ff
Show file tree
Hide file tree
Showing 18 changed files with 12,272 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}
14 changes: 14 additions & 0 deletions React InstantSearch Hooks Native/getting-started/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
node_modules/
.expo/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/

# macOS
.DS_Store
66 changes: 66 additions & 0 deletions React InstantSearch Hooks Native/getting-started/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useRef, useState } from 'react';
import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-hooks';

import { InfiniteHits } from './src/InfiniteHits';
import { SearchBox } from './src/SearchBox';
import { Highlight } from './src/Highlight';
import { Filters } from './src/Filters';
import { ProductHit } from './types/ProductHit';

const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);

export default function App() {
const [isModalOpen, setModalOpen] = useState(false);
const listRef = useRef<FlatList>(null);

function scrollToTop() {
listRef.current?.scrollToOffset({ animated: false, offset: 0 });
}

return (
<SafeAreaView style={styles.safe}>
<StatusBar style="light" />
<View style={styles.container}>
<InstantSearch searchClient={searchClient} indexName="instant_search">
<SearchBox onChange={scrollToTop} />
<Filters
isModalOpen={isModalOpen}
onToggleModal={() => setModalOpen((isOpen) => !isOpen)}
onChange={scrollToTop}
/>
<InfiniteHits ref={listRef} hitComponent={Hit} />
</InstantSearch>
</View>
</SafeAreaView>
);
}

type HitProps = {
hit: ProductHit;
};

function Hit({ hit }: HitProps) {
return (
<Text>
<Highlight hit={hit} attribute="name" />
</Text>
);
}

const styles = StyleSheet.create({
safe: {
flex: 1,
backgroundColor: '#252b33',
},
container: {
flex: 1,
backgroundColor: '#ffffff',
flexDirection: 'column',
},
});
19 changes: 19 additions & 0 deletions React InstantSearch Hooks Native/getting-started/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ais-ecommerce-demo-app

_This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._

## Get started

To run this project locally, install the dependencies and run the local server:

```sh
npm install
npm start
```

Alternatively, you may use [Yarn](https://http://yarnpkg.com/):

```sh
yarn
yarn start
```
30 changes: 30 additions & 0 deletions React InstantSearch Hooks Native/getting-started/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"expo": {
"name": "ais-ecommerce-demo-app",
"slug": "ais-ecommerce-demo-app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
31 changes: 31 additions & 0 deletions React InstantSearch Hooks Native/getting-started/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "ais-ecommerce-demo-app",
"version": "1.0.0",
"private": true,
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"algoliasearch": "4.12.1",
"expo": "~44.0.0",
"expo-status-bar": "~1.2.0",
"instantsearch.js": "4.38.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-instantsearch-hooks": "6.22.0",
"react-native": "0.64.3",
"react-native-web": "0.17.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@types/react": "~17.0.21",
"@types/react-native": "~0.64.12",
"expo-cli": "5.1.1",
"typescript": "~4.3.5"
}
}
161 changes: 161 additions & 0 deletions React InstantSearch Hooks Native/getting-started/src/Filters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React from 'react';
import {
StyleSheet,
SafeAreaView,
Modal,
Text,
TouchableOpacity,
View,
Button,
} from 'react-native';
import {
useClearRefinements,
useCurrentRefinements,
useRefinementList,
} from 'react-instantsearch-hooks';

type FiltersProps = {
isModalOpen: boolean;
onToggleModal: () => void;
onChange: () => void;
};

export function Filters({
isModalOpen,
onToggleModal,
onChange,
}: FiltersProps) {
const { items, refine } = useRefinementList({ attribute: 'brand' });
const { canRefine: canClear, refine: clear } = useClearRefinements();
const { items: currentRefinements } = useCurrentRefinements();
const totalRefinements = currentRefinements.reduce(
(acc, { refinements }) => acc + refinements.length,
0
);

return (
<>
<TouchableOpacity style={styles.filtersButton} onPress={onToggleModal}>
<Text style={styles.filtersButtonText}>Filters</Text>
{totalRefinements > 0 && (
<View style={styles.itemCount}>
<Text style={styles.itemCountText}>{totalRefinements}</Text>
</View>
)}
</TouchableOpacity>

<Modal animationType="slide" visible={isModalOpen}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.title}>
<Text style={styles.titleText}>Brand</Text>
</View>
<View style={styles.list}>
{items.map((item) => {
return (
<TouchableOpacity
key={item.value}
onPress={() => {
refine(item.value);
onChange();
}}
style={styles.item}
>
<Text
style={{
...styles.labelText,
fontWeight: item.isRefined ? '800' : '400',
}}
>
{item.label}
</Text>
<View style={styles.itemCount}>
<Text style={styles.itemCountText}>{item.count}</Text>
</View>
</TouchableOpacity>
);
})}
</View>
</View>
<View style={styles.filterListButtonContainer}>
<View style={styles.filterListButton}>
<Button
onPress={() => {
clear();
onChange();
onToggleModal();
}}
title="Clear all"
color="#252b33"
disabled={!canClear}
/>
</View>
<View style={styles.filterListButton}>
<Button
onPress={onToggleModal}
title="See results"
color="#252b33"
/>
</View>
</View>
</SafeAreaView>
</Modal>
</>
);
}

const styles = StyleSheet.create({
container: {
padding: 18,
backgroundColor: '#ffffff',
},
title: {
alignItems: 'center',
},
titleText: {
fontSize: 32,
},
list: {
marginTop: 32,
},
item: {
paddingVertical: 12,
flexDirection: 'row',
justifyContent: 'space-between',
borderBottomWidth: 1,
borderColor: '#ddd',
alignItems: 'center',
},
itemCount: {
backgroundColor: '#252b33',
borderRadius: 24,
paddingVertical: 4,
paddingHorizontal: 8,
marginLeft: 4,
},
itemCountText: {
color: '#ffffff',
fontWeight: '800',
},
labelText: {
fontSize: 16,
},
filterListButtonContainer: {
flexDirection: 'row',
},
filterListButton: {
flex: 1,
alignItems: 'center',
marginTop: 18,
},
filtersButton: {
paddingVertical: 18,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
filtersButtonText: {
fontSize: 18,
textAlign: 'center',
},
});
Loading

0 comments on commit 71710ff

Please sign in to comment.