diff --git a/App/Components/ListProduct.js b/App/Components/ListProduct.js new file mode 100644 index 0000000..1f35679 --- /dev/null +++ b/App/Components/ListProduct.js @@ -0,0 +1,22 @@ +import React, { memo, useContext } from 'react' +import { TouchableOpacity,Image, View, Text } from 'react-native' +import styles from './Styles/ListProductStyle' +import { NavigationContext } from "react-navigation" +import Format from '../Lib/NumberFormat' + +const ListProduct = (props) => { + const {thumb, title, price, press, ...restProps} = props + const navigation = useContext(NavigationContext) + + return ( + + + + {title} + {'Rp' + new Format().formatMoney(price)} + + + ) +} + +export default memo(ListProduct) diff --git a/App/Components/Styles/ListProductStyle.js b/App/Components/Styles/ListProductStyle.js new file mode 100644 index 0000000..698ed3c --- /dev/null +++ b/App/Components/Styles/ListProductStyle.js @@ -0,0 +1,11 @@ +import { connect } from "../../Lib/OsmiProvider" + +export default connect({ + card: "bg-white rounded-md shadow-md p-3 row items-center justify-start mb-3", + thumb: "rounded-md mr-3 w-100 h-100 justify-center", + content: "flex flex-wrap", + title: "text-base font-bold mb-1 flex-wrap", + price: "text-sm", + btnBuy: "bg-blue-500 rounded-md px-3 py-1 self-start", + btnBuyLabel: "text-white" +}) \ No newline at end of file diff --git a/App/Config/ReactotronConfig.js b/App/Config/ReactotronConfig.js index 8762a3f..44c1338 100644 --- a/App/Config/ReactotronConfig.js +++ b/App/Config/ReactotronConfig.js @@ -5,7 +5,7 @@ import { reactotronRedux as reduxPlugin } from 'reactotron-redux' import sagaPlugin from 'reactotron-redux-saga' const reactotron = Reactotron - .configure({ name: 'Ignite App', host: '192.168.100.8' }) + .configure({ name: 'Ignite App', host: '192.168.43.125' }) .useReactNative() .use(reduxPlugin({ onRestore: Immutable })) .use(sagaPlugin()) diff --git a/App/Containers/Home.js b/App/Containers/Home.js index 5e0a5b7..5d8be40 100644 --- a/App/Containers/Home.js +++ b/App/Containers/Home.js @@ -11,6 +11,7 @@ import { } from 'react-native' import { connect } from "react-redux"; import ProductsActions from "../Redux/ProductsRedux"; +import ListProduct from '../Components/ListProduct' import styles from './Styles/HomeStyle' import HeaderStyle from "../Navigation/Styles/NavigationStyles"; @@ -29,16 +30,7 @@ const Home = props => { } const renderItem = ({ item, index }) => ( - - - - {item?.title} - {item?.price} - - Beli - - - + alert('Beli')} /> ) const onEndReached = async (distance) => { diff --git a/App/Containers/Products.js b/App/Containers/Products.js index 93ca590..ff3d73a 100644 --- a/App/Containers/Products.js +++ b/App/Containers/Products.js @@ -1,28 +1,68 @@ -import React from 'react' -import { ScrollView, Text } from 'react-native' +import React, {useEffect, useState} from 'react' +import { SafeAreaView, ActivityIndicator, RefreshControl, FlatList, Image, View, Text } from 'react-native' import { connect } from 'react-redux' -// Add Actions - replace 'Your' with whatever your reducer is called :) -// import YourActions from '../Redux/YourRedux' +import CategoryActions from "../Redux/CategoryRedux"; // Styles import styles from './Styles/ProductsStyle' +import { apply } from '../Lib/OsmiProvider'; + +const Products = props => { + const {category} = props + const [refreshing, setRefreshing] = useState(false) + + useEffect(() => { + props.getCategory({}) + }, []) + + const pullToRefresh = () => { + props.getCategory({}) + } + + const renderItem = ({ item, index }) => ( + + + + {item.title} + {item.desc} + + + ) + + console.tron.log("=== ini titid ===", props.category) -const Products = () => { return ( - - Products Container - + + {category?.fetching ? ( + + + + ) : ( + index.toString()} + refreshControl={ + pullToRefresh()} /> + } + renderItem={renderItem} + ListEmptyComponent={() =>( + + Tidak ada data ditampilkam + + )} + /> + )} + ) } -const mapStateToProps = (state) => { - return { - } -} +const mapStateToProps = (state) => ({ + category: state.category.list +}) -const mapDispatchToProps = (dispatch) => { - return { - } -} +const mapDispatchToProps = (dispatch) => ({ + getCategory: value => dispatch(CategoryActions.getCategoryRequest(value)) +}) export default connect(mapStateToProps, mapDispatchToProps)(Products) diff --git a/App/Containers/Styles/HomeStyle.js b/App/Containers/Styles/HomeStyle.js index 2fb2f4f..40529a2 100644 --- a/App/Containers/Styles/HomeStyle.js +++ b/App/Containers/Styles/HomeStyle.js @@ -1,12 +1,5 @@ import { connect } from "../../Lib/OsmiProvider" export default connect({ - emptyState: "flex items-center justify-center", - card: "bg-white rounded-md shadow-md p-3 row items-start mb-3", - thumb: "rounded-md mr-3 w-100 h-100", - content: "flex flex-wrap", - title: "text-base font-bold mb-1 flex-wrap", - price: "text-sm", - btnBuy: "bg-blue-500 rounded-md px-3 py-1 self-start", - btnBuyLabel: "text-white" + emptyState: "flex items-center justify-center" }) \ No newline at end of file diff --git a/App/Containers/Styles/ProductsStyle.js b/App/Containers/Styles/ProductsStyle.js index 3144a3e..37faf37 100644 --- a/App/Containers/Styles/ProductsStyle.js +++ b/App/Containers/Styles/ProductsStyle.js @@ -1,10 +1,8 @@ -import { StyleSheet } from 'react-native' -import { Colors, Metrics } from '../../Themes/' +import { connect } from "../../Lib/OsmiProvider" -export default StyleSheet.create({ - container: { - flex: 1, - marginTop: Metrics.navBarHeight, - backgroundColor: Colors.background - } -}) +export default connect({ + card: 'row p-5 bg-white m-3 rounded-md items-center justify-start', + thumb: 'w-100 h-100 mr-5 rounded', + content: 'flex flex-wrap', + title: 'text-lg font-bold mb-1' +}) \ No newline at end of file diff --git a/App/Lib/NumberFormat.js b/App/Lib/NumberFormat.js new file mode 100644 index 0000000..6e5db96 --- /dev/null +++ b/App/Lib/NumberFormat.js @@ -0,0 +1,101 @@ +export default class TextUtil { + strReplace = (source, replace, replaceWith) => { + var value = source + var i = 0 + for (i; i < value.length; i++) { + value = value.replace(replace, replaceWith) + } + console.log(value) + return value; + } + + upperCaseString = (i) => { + if (typeof i === 'string') { + return i.toUpperCase() + } + return i + } + + formattingNumber = (i) => { + if (typeof i === 'number') { + return i.toLocaleString(navigator.language, { minimumFractionDigits: 0 }); + } + return i + } + + validateEmail = (text) => { + let reg = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; + if (reg.test(text) === false) { + return false; + } else { + return true; + } + } + + getListYear() { + var currentYear = new Date().getFullYear(), years = []; + var startYear = 2000; + while (startYear <= currentYear) { + years.push(startYear++); + } + return years; + } + + getDate(value, newFormat = null) { + if (newFormat == null) { + newFormat = 'DD MMMM YYYY' + } + let date = moment(value, formatDateDefault).format(newFormat) + return date + } + + getCurrentDate() { + let date = moment(new Date, 'DD-MM-YYYY').format(); + return date + } + + getDateTime(value) { + let date = moment(value, formatDateDefault).format('DD MMMM YYYY HH:mm:ss') + return date + } + + getDateTime2(value) { + let date = moment(value, formatDateDefault).format('DD MMMM YYYY HH:mm') + return date + } + + getFullDay(value) { + let date = moment(value, formatDateDefault).format('dddd, DD MMMM YYYY') + return date + } + + getTime(value) { + let date = moment(value, formatDateDefault).format('HH:mm:ss') + return date + } + + getHour(value) { + let date = moment(value, formatDateDefault).format('HH:mm') + return date + } + + formatMoney(num) { + num = num + "" + + if (num == "" || num == "0") + return ""; + + num = num.replace(/\./g, ""); + var num_parts = num.toString().split("."); + num_parts[0] = num_parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, "."); + return num_parts.join("."); + } + + moneytoInt(num) { + if (num) { + return num.replace(/\./g, ""); + } else { + return 0; + } + } +} \ No newline at end of file diff --git a/App/Redux/CategoryRedux.js b/App/Redux/CategoryRedux.js new file mode 100644 index 0000000..70b1bd7 --- /dev/null +++ b/App/Redux/CategoryRedux.js @@ -0,0 +1,40 @@ +import { createReducer, createActions } from 'reduxsauce' +import Immutable from 'seamless-immutable' + +/* ------------- Types and Action Creators ------------- */ + +const { Types, Creators } = createActions({ + getCategoryRequest: ['data'], + getCategorySuccess: ['data'], + getCategoryFailure: ['error'] +}) + +export const CategoryTypes = Types +export default Creators + +/* ------------- Initial State ------------- */ + +export const INITIAL_STATE = Immutable({ + list: { data: [], fetching: false, error: null }, + detail: {data: null, fetching: false, error: null} +}) + +/* ------------- Reducers ------------- */ + +// request the data from an api +export const getCategoryRequest = (state, { data }) => + state.merge({ ...state, list: {...state.list, fetching: true, error: null} }) + +export const getCategorySuccess = (state, { data }) => + state.merge({ ...state, list: { ...state.list, data, fetching: false, error: null }}) + +export const getCategoryFailure = (state, { error }) => + state.merge({ ...state, list: {...state.list, fetching: false, error} }) + +/* ------------- Hookup Reducers To Types ------------- */ + +export const reducer = createReducer(INITIAL_STATE, { + [Types.GET_CATEGORY_REQUEST]: getCategoryRequest, + [Types.GET_CATEGORY_SUCCESS]: getCategorySuccess, + [Types.GET_CATEGORY_FAILURE]: getCategoryFailure +}) diff --git a/App/Redux/index.js b/App/Redux/index.js index 9602c1d..c9d50d3 100644 --- a/App/Redux/index.js +++ b/App/Redux/index.js @@ -9,7 +9,8 @@ export const reducers = combineReducers({ nav: require('./NavigationRedux').reducer, github: require('./GithubRedux').reducer, search: require('./SearchRedux').reducer, - products: require('./ProductsRedux').reducer + products: require('./ProductsRedux').reducer, + category: require('./CategoryRedux').reducer }) export default () => { diff --git a/App/Sagas/CategorySagas.js b/App/Sagas/CategorySagas.js new file mode 100644 index 0000000..926d74a --- /dev/null +++ b/App/Sagas/CategorySagas.js @@ -0,0 +1,14 @@ +import { call, put } from 'redux-saga/effects' +import CategoryActions from '../Redux/CategoryRedux' + +export function * getCategory (api, action) { + const { data } = action + const response = yield call(api.getCategory, data) + + if (response.ok) { + console.tron.log("=== titid ===", response) + yield put(CategoryActions.getCategorySuccess(response.data.data)) + } else { + yield put(CategoryActions.getCategoryFailure(response)) + } +} diff --git a/App/Sagas/index.js b/App/Sagas/index.js index e55d296..a69d88c 100644 --- a/App/Sagas/index.js +++ b/App/Sagas/index.js @@ -7,13 +7,15 @@ import DebugConfig from '../Config/DebugConfig' import { StartupTypes } from '../Redux/StartupRedux' import { GithubTypes } from '../Redux/GithubRedux' -import { ProductsTypes } from "../Redux/ProductsRedux"; +import { ProductsTypes } from "../Redux/ProductsRedux" +import { CategoryTypes } from "../Redux/CategoryRedux" /* ------------- Sagas ------------- */ import { startup } from './StartupSagas' import { getUserAvatar } from './GithubSagas' -import { getProducts, moreProducts } from "./ProductsSagas"; +import { getProducts, moreProducts } from "./ProductsSagas" +import { getCategory } from "./CategorySagas"; /* ------------- API ------------- */ @@ -30,5 +32,6 @@ export default function * root () { takeLatest(ProductsTypes.GET_PRODUCTS_REQUEST, getProducts, api), takeLatest(ProductsTypes.MORE_PRODUCTS_REQUEST, moreProducts, api), + takeLatest(CategoryTypes.GET_CATEGORY_REQUEST, getCategory, api) ]) } diff --git a/App/Services/Api.js b/App/Services/Api.js index d832e72..76c0ea7 100644 --- a/App/Services/Api.js +++ b/App/Services/Api.js @@ -39,6 +39,7 @@ const create = (baseURL = 'https://api.alfredo.my.id/api/v1') => { // const getProducts = data => api.get(`/products${data.params}`) + const getCategory = data => api.get(`/category`) // ------ // STEP 3 @@ -55,6 +56,7 @@ const create = (baseURL = 'https://api.alfredo.my.id/api/v1') => { return { // a list of the API functions from step 2 getProducts, + getCategory, api }