├── github
├── dana.png
├── ovo.png
└── paypal.png
├── .firebaserc
├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── assets
│ └── fonts
│ │ ├── materialdesignicons-webfont.eot
│ │ ├── materialdesignicons-webfont.ttf
│ │ ├── materialdesignicons-webfont.woff
│ │ └── materialdesignicons-webfont.woff2
├── .htaccess
├── manifest.json
└── index.html
├── src
├── assets
│ ├── img
│ │ ├── logo.png
│ │ └── default.png
│ └── style.css
├── global.js
├── setupTests.js
├── App.test.js
├── components
│ ├── FullScreen.js
│ ├── Loading.js
│ ├── FormatNumber.js
│ ├── Table.js
│ └── DefaultScreen.js
├── views
│ ├── Errors
│ │ ├── ErrorDevice.js
│ │ ├── Error404.js
│ │ └── Error.js
│ ├── Role
│ │ ├── ViewRole.js
│ │ ├── AddRole.js
│ │ └── EditRole.js
│ ├── Product
│ │ └── ViewProduct.js
│ ├── User
│ │ └── ViewUser.js
│ ├── Expense
│ │ └── ViewExpense.js
│ ├── Login.js
│ ├── Supplier
│ │ ├── AddSupplier.js
│ │ └── EditSupplier.js
│ ├── Purchase
│ │ └── ViewPurchase.js
│ └── Sales
│ │ └── ViewSales.js
├── store
│ ├── reducer
│ │ ├── checkUserReducer.js
│ │ ├── permissionReducer.js
│ │ ├── registerReducer.js
│ │ ├── rootReducer.js
│ │ ├── loginReducer.js
│ │ ├── stockReducer.js
│ │ ├── settingReducer.js
│ │ ├── reportReducer.js
│ │ ├── expenseReducer.js
│ │ ├── roleReducer.js
│ │ ├── unitReducer.js
│ │ ├── userReducer.js
│ │ ├── salesReducer.js
│ │ ├── categoryReducer.js
│ │ ├── customerReducer.js
│ │ ├── supplierReducer.js
│ │ ├── purchaseReducer.js
│ │ ├── discountReducer.js
│ │ └── productReducer.js
│ └── actions
│ │ ├── PermissionAction.js
│ │ ├── StockActions.js
│ │ ├── SettingActions.js
│ │ ├── AuthActions.js
│ │ ├── PurchaseActions.js
│ │ └── ReportActions.js
├── index.js
├── App.js
└── serviceWorker.js
├── firebase.json
├── .gitignore
├── package.json
├── .firebase
├── hosting.cHVibGlj.cache
└── hosting.YnVpbGQ.cache
└── README.md
/github/dana.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/github/dana.png
--------------------------------------------------------------------------------
/github/ovo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/github/ovo.png
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "kasir-kita-1190d"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/github/paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/github/paypal.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/src/assets/img/logo.png
--------------------------------------------------------------------------------
/src/assets/img/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/src/assets/img/default.png
--------------------------------------------------------------------------------
/public/assets/fonts/materialdesignicons-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/assets/fonts/materialdesignicons-webfont.eot
--------------------------------------------------------------------------------
/public/assets/fonts/materialdesignicons-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/assets/fonts/materialdesignicons-webfont.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/materialdesignicons-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/assets/fonts/materialdesignicons-webfont.woff
--------------------------------------------------------------------------------
/public/assets/fonts/materialdesignicons-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kasirkita/Kasir-Kita/HEAD/public/assets/fonts/materialdesignicons-webfont.woff2
--------------------------------------------------------------------------------
/src/global.js:
--------------------------------------------------------------------------------
1 | let url
2 |
3 | if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
4 | url = 'http://localhost:8000/api'
5 | } else {
6 | url = 'https://kasir-kita.herokuapp.com/api'
7 | }
8 |
9 | export { url }
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | RewriteEngine On
4 | RewriteBase /
5 | RewriteRule ^index\.html$ - [L]
6 | RewriteCond %{REQUEST_FILENAME} !-f
7 | RewriteCond %{REQUEST_FILENAME} !-d
8 | RewriteCond %{REQUEST_FILENAME} !-l
9 | RewriteRule . /index.html [L]
10 |
11 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render();
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/components/FullScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 |
3 | class FullScreen extends Component {
4 | render() {
5 | return (
6 |
7 | {this.props.children}
8 |
9 | )
10 | }
11 | }
12 |
13 | export default FullScreen
14 |
--------------------------------------------------------------------------------
/src/components/Loading.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 |
3 | class Loading extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 | }
12 |
13 | export default Loading
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/views/Errors/ErrorDevice.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | function ErrorDevice() {
4 | return (
5 |
6 |
7 |
8 |
9 |
Mohon maaf, aplikasi nya hanya bisa dilihat di desktop saja
10 |
11 | :'(
12 |
13 |
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default ErrorDevice
21 |
--------------------------------------------------------------------------------
/src/views/Errors/Error404.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from 'react-router-dom'
3 |
4 | class Error404 extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
404 - Halaman tidak di temukan
10 |
Halaman yang anda cari hilang, atau tidak ditemukan
11 |
12 |
Kembali ke rumah
13 |
14 |
15 |
16 | )
17 | }
18 | }
19 |
20 | export default Error404
21 |
--------------------------------------------------------------------------------
/src/store/reducer/checkUserReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | userExists: null,
5 | error: null
6 | }
7 |
8 | const checkUserReducer = (state = initState, action) => {
9 | switch (action.type) {
10 | case 'CHECK_USER_PENDING':
11 | return {
12 | ...state,
13 | fetching: true
14 | }
15 | case 'CHECK_USER_SUCCESS':
16 | return {
17 | ...state,
18 | fetching: false,
19 | fetched: true,
20 | userExists: action.userExists
21 | }
22 | case 'CHECK_USER_FAILED':
23 | return {
24 | ...state,
25 | fetching: false,
26 | fetched: true,
27 | error: action.error
28 | }
29 | default:
30 | return state
31 | }
32 | }
33 |
34 | export default checkUserReducer
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import * as serviceWorker from './serviceWorker';
5 | import { Provider } from 'react-redux';
6 | import { createStore } from 'redux';
7 | import { applyMiddleware } from 'redux';
8 | import thunk from 'redux-thunk';
9 | import rootReducer from './store/reducer/rootReducer';
10 | import { ToastProvider } from 'react-toast-notifications'
11 |
12 | const store = createStore(rootReducer, applyMiddleware(thunk))
13 |
14 | ReactDOM.render(
15 |
16 |
17 |
18 |
19 | ,
20 | document.getElementById('root'));
21 |
22 | // If you want your app to work offline and load faster, you can change
23 | // unregister() to register() below. Note this comes with some pitfalls.
24 | // Learn more about service workers: https://bit.ly/CRA-PWA
25 | serviceWorker.unregister();
26 |
--------------------------------------------------------------------------------
/src/views/Errors/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from 'react-router-dom'
3 |
4 | class Error extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
{ this.props.code } - { this.props.title }
10 |
{this.props.message}
11 |
12 | {
13 | !this.props.connection && (
14 |
15 |
Kembali ke rumah
16 |
17 | )
18 | }
19 |
20 |
21 | )
22 | }
23 | }
24 |
25 | export default Error
26 |
--------------------------------------------------------------------------------
/src/store/reducer/permissionReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | permissions: [],
3 | fetching: false,
4 | fetched: false,
5 | error: null,
6 | type: null
7 | }
8 |
9 | const permissionReducer = (state = initState, action) => {
10 | switch (action.type) {
11 | case 'LIST_PERMISSION_PENDING':
12 | return {
13 | ...state,
14 | fetching: true,
15 | error: null
16 | }
17 | case 'LIST_PERMISSION_SUCCESS':
18 |
19 | return {
20 | ...state,
21 | fetching: false,
22 | fetched: true,
23 | permissions: action.data,
24 | success: true,
25 | type: 'list'
26 | }
27 |
28 | case 'LIST_PERMISSION_FAILED':
29 | return {
30 | ...state,
31 | fetching: false,
32 | fetched: true,
33 | error: action.error,
34 | message: action.error.data.message,
35 | success: false,
36 | type: 'list'
37 | }
38 | default:
39 | return state
40 | }
41 | }
42 |
43 | export default permissionReducer
--------------------------------------------------------------------------------
/src/components/FormatNumber.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import NumberFormat from 'react-number-format'
3 |
4 | class FormatNumber extends React.Component {
5 |
6 | handleChangeNumber = (e) => {
7 | const { handleChangeNumber = false } = this.props
8 |
9 | if (handleChangeNumber) {
10 | handleChangeNumber(e)
11 | }
12 | }
13 |
14 | render() {
15 | const { value, validate, name, type = false } = this.props
16 | return this.handleChangeNumber(e)} value={value} placeholder={`${sessionStorage.getItem('currency') !== 'null' ? sessionStorage.getItem('currency') : '' } ${sessionStorage.getItem('decimal_separator') !== 'null' ? `0${sessionStorage.getItem('decimal_separator')}0` : '00' } `} />
17 | }
18 | }
19 | export default FormatNumber
20 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { BrowserRouter, Route, Switch } from 'react-router-dom'
3 | import routes from './routes'
4 | import './assets/style.css'
5 | import Error404 from './views/Errors/Error404'
6 | import { isMobile } from 'react-device-detect'
7 | import ErrorDevice from './views/Errors/ErrorDevice'
8 |
9 | class App extends Component {
10 | render() {
11 |
12 | if (isMobile)
13 | return (
14 |
15 | )
16 | return (
17 |
18 |
19 | {
20 | routes.map((route, index) => {
21 | return ( {
26 | return (
27 |
28 |
29 |
30 | );
31 | }}
32 | />
33 | )
34 | })
35 | }
36 |
37 |
38 |
39 | )
40 | }
41 | }
42 |
43 | export default App
44 |
45 |
--------------------------------------------------------------------------------
/src/store/reducer/registerReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null
8 | }
9 |
10 | const registerReducer = (state = initState, action) => {
11 | switch (action.type) {
12 | case 'REGISTER_PENDING':
13 | return {
14 | ...state,
15 | fetching: true
16 | }
17 | case 'REGISTER_SUCCESS':
18 | sessionStorage.setItem('token', action.token)
19 | sessionStorage.setItem('name', action.data.name)
20 | sessionStorage.setItem('avatar', action.data.avatar)
21 | sessionStorage.setItem('email', action.data.email)
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | message: action.message,
28 | success: true
29 | }
30 | case 'REGISTER_FAILED':
31 | return {
32 | ...state,
33 | fetching: false,
34 | fetched: true,
35 | error: action.error,
36 | message: action.error.data.message,
37 | success: false
38 | }
39 | default:
40 | return state
41 | }
42 | }
43 |
44 | export default registerReducer
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "schedio",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.3.2",
8 | "@testing-library/user-event": "^7.1.2",
9 | "axios": "^0.19.2",
10 | "chart.js": "^2.9.3",
11 | "js-file-download": "^0.4.10",
12 | "moment": "^2.24.0",
13 | "react": "^16.12.0",
14 | "react-barcode": "^1.4.0",
15 | "react-bootstrap4-modal": "^1.7.4",
16 | "react-chartjs-2": "^2.9.0",
17 | "react-datepicker": "^2.12.0",
18 | "react-device-detect": "^1.11.14",
19 | "react-dom": "^16.12.0",
20 | "react-dropzone": "^10.2.1",
21 | "react-number-format": "^4.4.1",
22 | "react-redux": "^7.2.0",
23 | "react-router-dom": "^5.1.2",
24 | "react-scripts": "3.3.1",
25 | "react-select": "^3.0.8",
26 | "react-toast-notifications": "^2.4.0",
27 | "redux": "^4.0.5",
28 | "redux-thunk": "^2.3.0"
29 | },
30 | "scripts": {
31 | "start": "react-scripts start",
32 | "build": "react-scripts build",
33 | "test": "react-scripts test",
34 | "eject": "react-scripts eject"
35 | },
36 | "eslintConfig": {
37 | "extends": "react-app"
38 | },
39 | "browserslist": {
40 | "production": [
41 | ">0.2%",
42 | "not dead",
43 | "not op_mini all"
44 | ],
45 | "development": [
46 | "last 1 chrome version",
47 | "last 1 firefox version",
48 | "last 1 safari version"
49 | ]
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/store/actions/PermissionAction.js:
--------------------------------------------------------------------------------
1 | import { url } from "../../global"
2 | import Axios from "axios"
3 |
4 | const getListPermission = () => {
5 | return (dispatch, getState) => {
6 |
7 | dispatch({
8 | type: 'LIST_PERMISSION_PENDING',
9 | })
10 |
11 | Axios.get(`${url}/permission/list`, {
12 | headers: {
13 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
14 | }
15 | }).then(res => {
16 | dispatch({
17 | type: 'LIST_PERMISSION_SUCCESS',
18 | data: res.data.data,
19 | success: true
20 | })
21 | }).catch(error => {
22 | if (!error.response) {
23 | dispatch({
24 | type: 'LIST_PERMISSION_FAILED',
25 | error: {
26 | status: null,
27 | connection: true,
28 | statusText: 'Koneksi Terputus',
29 | data: {
30 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
31 | }
32 | }
33 | })
34 |
35 | } else {
36 |
37 | dispatch({
38 | type: 'LIST_PERMISSION_FAILED',
39 | error: error.response,
40 | message: error.response.data.message
41 | })
42 | }
43 | })
44 | }
45 | }
46 |
47 | export { getListPermission }
--------------------------------------------------------------------------------
/src/store/reducer/rootReducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux"
2 | import checkUserReducer from "./checkUserReducer"
3 | import registerReducer from "./registerReducer"
4 | import loginReducer from "./loginReducer"
5 | import productReducer from "./productReducer"
6 | import categoryReducer from "./categoryReducer"
7 | import unitReducer from "./unitReducer"
8 | import roleReducer from "./roleReducer"
9 | import permissionReducer from "./permissionReducer"
10 | import userReducer from "./userReducer"
11 | import customerReducer from "./customerReducer"
12 | import supplierReducer from "./supplierReducer"
13 | import settingReducer from "./settingReducer"
14 | import salesReducer from "./salesReducer"
15 | import discountReducer from "./discountReducer"
16 | import purchaseReducer from "./purchaseReducer"
17 | import expenseReducer from "./expenseReducer"
18 | import stockReducer from "./stockReducer"
19 | import reportReducer from "./reportReducer"
20 |
21 | const rootReducer = combineReducers({
22 | checkUser: checkUserReducer,
23 | register: registerReducer,
24 | login: loginReducer,
25 | product: productReducer,
26 | category: categoryReducer,
27 | unit: unitReducer,
28 | role: roleReducer,
29 | permission: permissionReducer,
30 | user: userReducer,
31 | customer: customerReducer,
32 | supplier: supplierReducer,
33 | setting: settingReducer,
34 | sales: salesReducer,
35 | discount: discountReducer,
36 | purchase: purchaseReducer,
37 | expense: expenseReducer,
38 | stock: stockReducer,
39 | report: reportReducer
40 | })
41 |
42 | export default rootReducer
--------------------------------------------------------------------------------
/src/store/reducer/loginReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | redirect: '/'
9 | }
10 |
11 | const loginReducer = (state = initState, action) => {
12 | switch (action.type) {
13 | case 'LOGIN_PENDING':
14 | return {
15 | ...state,
16 | fetching: true,
17 | fetched: false
18 | }
19 | case 'LOGIN_SUCCESS':
20 | sessionStorage.setItem('token', action.token)
21 | sessionStorage.setItem('name', action.data.name)
22 | sessionStorage.setItem('avatar', action.data.avatar)
23 | sessionStorage.setItem('email', action.data.email)
24 | sessionStorage.setItem('permissions', JSON.stringify(action.permissions))
25 | return {
26 | ...state,
27 | fetching: false,
28 | fetched: true,
29 | data: action.data,
30 | message: action.message,
31 | success: true,
32 | error: null,
33 | redirect: `/${action.redirect.type}`
34 | }
35 | case 'LOGIN_FAILED':
36 | return {
37 | ...state,
38 | fetching: false,
39 | fetched: true,
40 | error: action.error,
41 | message: action.error.data.message,
42 | success: false
43 | }
44 | default:
45 | return state
46 | }
47 | }
48 |
49 | export default loginReducer
--------------------------------------------------------------------------------
/.firebase/hosting.cHVibGlj.cache:
--------------------------------------------------------------------------------
1 | favicon.ico,1581162026634,a08fa4488c3ecef62d9effd03b3a989929bdcbecf5e905941f9034a15bd3dba3
2 | logo192.png,1581162026635,caff018b7f1e8fd481eb1c50d75b0ef236bcd5078b1d15c8bb348453fee30293
3 | logo512.png,1581162026636,191fc21360b4ccfb1cda11a1efb97f489ed22672ca83f4064316802bbfdd750e
4 | manifest.json,1581162026636,341d52628782f8ac9290bbfc43298afccb47b7cbfcee146ae30cf0f46bc30900
5 | robots.txt,1581162026637,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2
6 | assets/css/bootstrap.min.css,1581164928910,440f8e33b94eaccd2941aaa9cdd915350424b093984e8de8fd6fce2091cafb39
7 | assets/css/materialdesignicons.min.css,1580828340000,3affd4812b5caca1b35510c85751a3ddb0727e3b8174637fa0d448ea067e5bba
8 | assets/fonts/materialdesignicons-webfont.eot,1580828340000,4a87f1aa6d5439f247add95353dc64d888a3ea2d0a539d543d6e27989894205f
9 | assets/fonts/materialdesignicons-webfont.ttf,1580828340000,a42ef9e82643cad0a623e2fe4769b13d3f4dadf089b3ad6da55893b3a97e106f
10 | assets/fonts/materialdesignicons-webfont.woff,1580828340000,0bfe1621d69ffba8eed14ec77fc9bfabc68ef29cb7caf79b33560fcce13a878f
11 | assets/fonts/materialdesignicons-webfont.woff2,1580828340000,62984f6906f91fcb64e77b9a5235253375a4f106e6dec1ee501a0e59b032f2c1
12 | assets/js/bootstrap.min.js,1581164942970,745cfe3216675d98b2c01d26e1ce1a5838c09a9bf0075f7d3a4bbbde1f750309
13 | assets/js/jquery-3.4.1.slim.min.js,1581162228317,d9beae6bd087c5b78316cc58ac27ae9c1d0517b8335d4b29ff8a36e3c8f1ea11
14 | assets/js/popper.min.js,1581162248414,dd91bc46140a9a8d025ad3e9dfe640f11adf34d3844e8e4f31495ac5669b3791
15 | index.html,1583645083013,81a968975329521d7fcbbfb69c72cfb9bdeb0e882f19802b9948bba067399dec
16 |
--------------------------------------------------------------------------------
/src/components/Table.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class Table extends React.Component {
4 | render() {
5 |
6 | const {theads, ordering, handleSorting} = this.props;
7 |
8 | const tHead = theads.map((head, index) => {
9 | return (
10 |
11 | {head.value}
12 | {
13 | head.sortable && (
14 |
15 | {
16 | ordering.type === head.name ?
17 | ()
18 | :
19 | ()
20 | }
21 |
22 |
23 | )
24 | }
25 | |
26 | )
27 | })
28 |
29 | return (
30 |
31 |
32 |
33 | {tHead}
34 |
35 |
36 |
37 | {this.props.children}
38 |
39 |
40 | )
41 | }
42 | }
43 |
44 | export default Table;
--------------------------------------------------------------------------------
/src/store/reducer/stockReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | stock: null
10 | }
11 |
12 | const stockReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_STOCK_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_STOCK_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_STOCK_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_STOCK_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_STOCK_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | carts: action.data,
54 | type: 'save',
55 | success: true
56 | }
57 |
58 | case 'SAVE_STOCK_FAILED':
59 | return {
60 | ...state,
61 | fetching: false,
62 | fetched: true,
63 | error: action.error,
64 | message: action.message,
65 | type: 'save',
66 | success: false
67 | }
68 | default:
69 | return state
70 | }
71 | }
72 |
73 | export default stockReducer
--------------------------------------------------------------------------------
/src/store/reducer/settingReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | setting: null,
10 | }
11 |
12 | const settingReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'SAVE_SETTING_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | }
19 | case 'SAVE_SETTING_SUCCESS':
20 |
21 | return {
22 | ...state,
23 | fetching: false,
24 | fetched: true,
25 | message: action.message,
26 | type: 'save',
27 | success: true
28 | }
29 |
30 | case 'SAVE_SETTING_FAILED':
31 | return {
32 | ...state,
33 | fetching: false,
34 | fetched: true,
35 | error: action.error,
36 | message: action.message,
37 | type: 'save',
38 | success: false
39 | }
40 | case 'GET_SETTING_PENDING':
41 | return {
42 | ...state,
43 | fetching: true,
44 | error: null
45 | }
46 | case 'GET_SETTING_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | type: 'get',
53 | setting: action.data,
54 | success: true
55 | }
56 |
57 | case 'GET_SETTING_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'get',
65 | success: false
66 | }
67 | case 'UPDATE_SETTING_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | default:
73 | return state
74 | }
75 | }
76 |
77 | export default settingReducer
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Kasir Kita v.2.0
2 | Kasir Kita, aplikasi POS gratis dibuat menggunakan Reactjs
3 |
4 | ## Cara menginstall
5 |
6 | ### Step 1 Menginstall Package dan Mengatur URL
7 | Silahkan clone repository ini, atau download, setelah itu gunakan perintah `yarn install` atau `npm install`. Setelah itu silahkan buka file `global.js` yang ada pada directory `./src/global.js` lalu ubah url ke url aplikasi backend, untuk backend nya ada di repository ini `https://github.com/kasirkita/Kasir-Kita-BE` setelah itu gunakan perintah `yarn start` atau `npm start` untuk menyalakan servis dalam model development
8 |
9 | ### Step 2 Mengatur Node.js untuk servis printer
10 | Silahkan buka kembali file `global.js` yang ada pada directory `./src/global.js` lalu ubah url nya sesuai dengan url yang kalian punya, untuk mendownload servis node.js printer ada di repository `https://github.com/kasirkita/Kasir-Kita-Printer`
11 |
12 | ### Step 3 Build aplikasi
13 | Silahkan ketikan perinta `yarn build` atau `npm build` lalu akan otomatis hasil build ada di folder `./build` silahkan untuk melokasikan folder ke http servis yang kalian miliki
14 |
15 | ## Lisensi
16 | Aplikasi ini 100% Gratis, tetapi jika menginginkan penambahan fitur dan atau cara menjalakan aplikasi silahkan chat melalui whatsapp 089611081675
17 | Adapun ketentuan pada penggunaan aplikasi ini adalah
18 |
19 | - Tidak boleh dikomersilkan dalam bentuk apapun tanpa sepengetahuan author
20 | - Tidak boleh menyalin dan menyebarkan ulang kode tanpa sepengetahuan author
21 | - Tidak boleh menghapus credit pada aplikasi
22 |
23 | ## Dukungan
24 | Silahkan berkonstribusi atau mengirimkan issue untuk pengembangan, silahkan gunakan opsi fork dan lakukan PR untuk menjadi kontributor
25 |
26 | Jika merasa aplikasi ini berguna, silakan melakukan dukungan dengan cara berdonasi seikhlasnya dibawah ini
27 |
28 |
29 |
30 |
31 |
32 |
33 | |
34 |
35 |
36 | |
37 |
38 |
39 | |
40 |
41 |
42 |
43 |
44 |
45 | ## Kontributor
46 |
47 | - Razaq Hakim
48 | - Yulianto Saparudin
49 | - Rega Rivaldi
50 | - Muhammad Irfan
51 |
--------------------------------------------------------------------------------
/src/views/Role/ViewRole.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { connect } from 'react-redux'
3 | import { Link } from 'react-router-dom'
4 | import { getRole } from '../../store/actions/RoleActions'
5 | import { getListPermission } from '../../store/actions/PermissionAction'
6 |
7 | class ViewRole extends Component {
8 |
9 | async componentDidMount() {
10 | await this.props.getListPermission()
11 | await this.props.getRole(this.props.match.params.id)
12 | }
13 |
14 | render() {
15 | const { role, permissions } = this.props
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
{ role && role.name }
23 |
24 |
25 | Kembali
26 |
27 |
28 |
29 |
30 |
31 |
Izin
32 |
33 | {
34 | permissions && permissions.map(permission => {
35 | return (
36 |
37 | {permission.name} {role && role.perms[permission.slug] ? : }
38 |
39 | )
40 | })
41 | }
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | )
51 | }
52 | }
53 |
54 | const mapStateToProps = state => {
55 | return {
56 | ...state,
57 | role: state.role.role,
58 | permissions: state.permission.permissions
59 | }
60 | }
61 |
62 | const mapDispatchToProps = dispatch => {
63 | return {
64 | getRole: id => dispatch(getRole(id)),
65 | getListPermission: () => dispatch(getListPermission())
66 | }
67 | }
68 |
69 | export default connect(mapStateToProps, mapDispatchToProps)(ViewRole)
70 |
--------------------------------------------------------------------------------
/src/views/Product/ViewProduct.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { getProduct } from '../../store/actions/ProductActions'
4 | import { connect } from 'react-redux'
5 |
6 | class ViewProduct extends Component {
7 | componentDidMount() {
8 | this.props.getProduct(this.props.match.params.id)
9 | }
10 | render() {
11 | const { product } = this.props
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
{ product && product.name }
19 |
20 |
21 | Kembali
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | | Kode |
32 | {product && product.code} |
33 | Harga Jual |
34 | { product && product.price_formatted } |
35 |
36 |
37 | | Harga Beli |
38 | { product && product.cost_formatted } |
39 | Harga Grosir |
40 | { product && product.wholesale_formatted } |
41 |
42 |
43 | | Kategori |
44 | { product && product.category && product.category.name } |
45 | Stok |
46 | { product && product.qty && product.qty.amount }/{ product && product.unit && product.unit.name } |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | )
55 | }
56 | }
57 |
58 | const mapStateToProps = state => {
59 | return {
60 | ...state,
61 | product: state.product.product
62 | }
63 | }
64 |
65 | const mapDispatchToProps = dispatch => {
66 | return {
67 | getProduct: id => dispatch(getProduct(id))
68 | }
69 | }
70 |
71 | export default connect(mapStateToProps, mapDispatchToProps)(ViewProduct)
72 |
--------------------------------------------------------------------------------
/.firebase/hosting.YnVpbGQ.cache:
--------------------------------------------------------------------------------
1 | asset-manifest.json,1586165366288,032e7ad784a4609aa78fd6cc193bcfcbe1ed7877eef4282ffe16f5af14624ba7
2 | favicon.ico,1586165345474,34c008d977103c880e85aa3cf8dd3a5bb96ae9fdc07faf5444efd2695dfee8b3
3 | logo192.png,1586165345474,32f6e4a3a8ad267f2e9784f9b295d5ed2f3fb4194082444fa6a6cd15015c5608
4 | index.html,1586165366288,7a3fdc9f8c8c204f104a0dfb80fd9e2ab7e10b0da3426ad26c2e5cb2efafbd46
5 | manifest.json,1586165345475,341d52628782f8ac9290bbfc43298afccb47b7cbfcee146ae30cf0f46bc30900
6 | logo512.png,1586165345475,b085731885e2f2b7691bfc19ddb8ef3b0131e76df3f02cde7bc6511d1b682387
7 | robots.txt,1586165345476,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2
8 | precache-manifest.18ea3eb43f45fb9a9c41a0b6957849c3.js,1586165366288,2b41cba26c1fc47c797c9ad386b7aefa29a2ecdaa9415b420c665fd4cdd4cd5b
9 | service-worker.js,1586165366288,11aca0ee129c80598ee52bbbeaae4a47b20e6b9055ceed4707cc664c9f70ed6f
10 | assets/js/bootstrap.min.js,1586165345471,6b5541588852d13957fd3757fa59079eff7af41e55b4002fadc37bda4a9099c2
11 | assets/js/popper.min.js,1586165345473,dd91bc46140a9a8d025ad3e9dfe640f11adf34d3844e8e4f31495ac5669b3791
12 | static/css/2.b90ce945.chunk.css,1586165366317,ebea2626a607164ac32d3d655e0a98eeba1f4170bf73d7206989a485ecd2ab01
13 | static/css/main.d3eb9bb3.chunk.css,1586165366290,add620f948e3797f158d1f4bf7a398e16da60603e3c730605c2376ccd9d449a9
14 | static/css/main.d3eb9bb3.chunk.css.map,1586165366316,f2a6791fd7a7a38678fb30362e450a1c72a74ddb99db5423003518dc21a12ba8
15 | static/css/2.b90ce945.chunk.css.map,1586165366316,7c47ca1122ec63c2c190263c439952407d4824945f1c7d5bf26f364149a0461b
16 | static/js/2.2a2f6937.chunk.js.LICENSE.txt,1586165366316,2c86e8128f3301795c0ae002bdcf998df9147aa14c080131acd8677ad76fe64d
17 | static/js/runtime-main.0a430e43.js,1586165366316,28283286d5f36a71b96dc826fc5dd068df005bea4b9684e1114694bcdc61eeec
18 | static/js/runtime-main.0a430e43.js.map,1586165366316,d8f5afbcfda42e1358a5c4df1be8a18712921da3027692f3608aa7d087d33317
19 | assets/js/jquery-3.4.1.slim.min.js,1586165345472,d9beae6bd087c5b78316cc58ac27ae9c1d0517b8335d4b29ff8a36e3c8f1ea11
20 | assets/css/bootstrap.min.css,1586165345431,440f8e33b94eaccd2941aaa9cdd915350424b093984e8de8fd6fce2091cafb39
21 | assets/css/materialdesignicons.min.css,1586165345436,3affd4812b5caca1b35510c85751a3ddb0727e3b8174637fa0d448ea067e5bba
22 | static/js/main.7e2a8d0e.chunk.js,1586165366291,d553b153e72823c10067e8b439f5a89d72f9bab4704ca3a75df7a123dd23b796
23 | assets/fonts/materialdesignicons-webfont.woff2,1586165345468,62984f6906f91fcb64e77b9a5235253375a4f106e6dec1ee501a0e59b032f2c1
24 | assets/fonts/materialdesignicons-webfont.woff,1586165345463,0bfe1621d69ffba8eed14ec77fc9bfabc68ef29cb7caf79b33560fcce13a878f
25 | static/js/2.2a2f6937.chunk.js,1586165366316,d5821b499b94cff303435425386da3d3b0e1d9d421eb5246a080a3d63a30db6f
26 | assets/fonts/materialdesignicons-webfont.eot,1586165345448,4a87f1aa6d5439f247add95353dc64d888a3ea2d0a539d543d6e27989894205f
27 | assets/fonts/materialdesignicons-webfont.ttf,1586165345456,a42ef9e82643cad0a623e2fe4769b13d3f4dadf089b3ad6da55893b3a97e106f
28 | static/js/main.7e2a8d0e.chunk.js.map,1586165366317,64992992a6b10a192878a60bd81ed01b204e2942dcb7f58eb015ce444ccd29e2
29 | static/js/2.2a2f6937.chunk.js.map,1586165366317,7b9e25abf4f5b715bb56de949a306e12a7e297c186878d41615a6d7577619e2e
30 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 | Kasir Kita
33 |
34 |
35 |
36 |
37 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
57 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/views/User/ViewUser.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { connect } from 'react-redux'
3 | import { Link } from 'react-router-dom'
4 | import { getUser } from '../../store/actions/UserActions'
5 |
6 | class ViewUser extends Component {
7 |
8 | async componentDidMount() {
9 | await this.props.getUser(this.props.match.params.id)
10 | }
11 |
12 | render() {
13 | const { user } = this.props
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
{ user && user.name }
21 |
22 |
23 | Kembali
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |

33 |
34 |
35 |
36 |
37 |
38 | | Nama: |
39 | {user && user.name} |
40 |
41 |
42 | | Email: |
43 | {user && user.email} |
44 | Nomor Telfon: |
45 | {user && user.phone_number} |
46 |
47 |
48 | | Peranan: |
49 | {user && user.role && user.role.name } |
50 | Tempat tanggal lahir: |
51 | {user && user.place_of_birth}, {user && user.date_of_birth_formatted} |
52 |
53 |
54 | | Alamat: |
55 | {user && user.address} |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | )
66 | }
67 | }
68 |
69 | const mapStateToProps = state => {
70 | return {
71 | ...state,
72 | user: state.user.user,
73 | }
74 | }
75 |
76 | const mapDispatchToProps = dispatch => {
77 | return {
78 | getUser: id => dispatch(getUser(id)),
79 | }
80 | }
81 |
82 | export default connect(mapStateToProps, mapDispatchToProps)(ViewUser)
83 |
--------------------------------------------------------------------------------
/src/store/reducer/reportReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | }
10 |
11 | const reportReducer = (state = initState, action) => {
12 | switch (action.type) {
13 | case 'FETCH_SALES_REPORT_PENDING':
14 | return {
15 | ...state,
16 | fetching: true,
17 | error: null
18 | }
19 | case 'FETCH_SALES_REPORT_SUCCESS':
20 |
21 | return {
22 | ...state,
23 | fetching: false,
24 | fetched: true,
25 | data: action.data,
26 | success: true,
27 | type: 'fetch'
28 | }
29 |
30 | case 'FETCH_SALES_REPORT_FAILED':
31 | return {
32 | ...state,
33 | fetching: false,
34 | fetched: true,
35 | error: action.error,
36 | message: action.error.data.message,
37 | success: false,
38 | type: 'fetch'
39 | }
40 | case 'FETCH_PURCHASE_REPORT_PENDING':
41 | return {
42 | ...state,
43 | fetching: true,
44 | error: null
45 | }
46 | case 'FETCH_PURCHASE_REPORT_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | data: action.data,
53 | success: true,
54 | type: 'fetch'
55 | }
56 |
57 | case 'FETCH_PURCHASE_REPORT_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.error.data.message,
64 | success: false,
65 | type: 'fetch'
66 | }
67 | case 'FETCH_EXPENSE_REPORT_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | error: null
72 | }
73 | case 'FETCH_EXPENSE_REPORT_SUCCESS':
74 |
75 | return {
76 | ...state,
77 | fetching: false,
78 | fetched: true,
79 | data: action.data,
80 | success: true,
81 | type: 'fetch'
82 | }
83 |
84 | case 'FETCH_EXPENSE_REPORT_FAILED':
85 | return {
86 | ...state,
87 | fetching: false,
88 | fetched: true,
89 | error: action.error,
90 | message: action.error.data.message,
91 | success: false,
92 | type: 'fetch'
93 | }
94 |
95 | case 'FETCH_STOCK_REPORT_PENDING':
96 | return {
97 | ...state,
98 | fetching: true,
99 | error: null
100 | }
101 | case 'FETCH_STOCK_REPORT_SUCCESS':
102 |
103 | return {
104 | ...state,
105 | fetching: false,
106 | fetched: true,
107 | data: action.data,
108 | success: true,
109 | type: 'fetch'
110 | }
111 |
112 | case 'FETCH_STOCK_REPORT_FAILED':
113 | return {
114 | ...state,
115 | fetching: false,
116 | fetched: true,
117 | error: action.error,
118 | message: action.error.data.message,
119 | success: false,
120 | type: 'fetch'
121 | }
122 | default:
123 | return state
124 | }
125 | }
126 |
127 | export default reportReducer
--------------------------------------------------------------------------------
/src/store/actions/StockActions.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios'
2 | import { url } from '../../global'
3 | import moment from 'moment'
4 |
5 | const fetchStock = (params) => {
6 | return (dispatch, getState) => {
7 |
8 | const {
9 | page,
10 | perpage,
11 | keyword,
12 | ordering,
13 | product_id,
14 | start_date,
15 | end_date
16 | } = params
17 |
18 | dispatch({
19 | type: 'FETCH_STOCK_PENDING'
20 | })
21 |
22 | Axios.get(`${url}/stock`, {
23 | params: {
24 | page,
25 | perpage,
26 | keyword,
27 | ordering,
28 | product_id,
29 | start_date: moment(start_date).format('YYYY-MM-DD'),
30 | end_date: moment(end_date).format('YYYY-MM-DD')
31 | },
32 | headers: {
33 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
34 | }
35 | }).then(res => {
36 |
37 | dispatch({
38 | type: 'FETCH_STOCK_SUCCESS',
39 | data: res.data.data,
40 | selected: res.data.selected
41 | })
42 |
43 | }).catch(error => {
44 |
45 | if (!error.response) {
46 | dispatch({
47 | type: 'FETCH_STOCK_FAILED',
48 | error: {
49 | status: null,
50 | connection: true,
51 | statusText: 'Koneksi Terputus',
52 | data: {
53 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
54 | }
55 | }
56 | })
57 |
58 | } else {
59 |
60 | dispatch({
61 | type: 'FETCH_STOCK_FAILED',
62 | error: error.response
63 | })
64 | }
65 |
66 | })
67 | }
68 | }
69 |
70 |
71 | const saveStock = (data) => {
72 | return (dispatch, getState) => {
73 |
74 | const {
75 | product_id,
76 | real_stock,
77 | description
78 | } = data
79 |
80 | dispatch({
81 | type: 'SAVE_STOCK_PENDING'
82 | })
83 |
84 | Axios.post(`${url}/stock`, {
85 | product_id,
86 | real_stock,
87 | description
88 | },
89 | {
90 | headers: {
91 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
92 | }
93 | }).then(res => {
94 |
95 | dispatch({
96 | type: 'SAVE_STOCK_SUCCESS',
97 | data: res.data.data,
98 | message: res.data.message
99 | })
100 |
101 | }).catch(error => {
102 |
103 | if (!error.response) {
104 | dispatch({
105 | type: 'SAVE_STOCK_FAILED',
106 | error: {
107 | status: null,
108 | connection: true,
109 | statusText: 'Koneksi Terputus',
110 | data: {
111 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
112 | }
113 | }
114 | })
115 |
116 | } else {
117 |
118 | dispatch({
119 | type: 'SAVE_STOCK_FAILED',
120 | error: error.response,
121 | message: error.response.data.message
122 | })
123 | }
124 |
125 | })
126 | }
127 | }
128 |
129 | export { fetchStock, saveStock }
--------------------------------------------------------------------------------
/src/store/reducer/expenseReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | expense: null,
10 | }
11 |
12 | const expenseReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_EXPENSE_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_EXPENSE_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_EXPENSE_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_EXPENSE_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_EXPENSE_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_EXPENSE_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_EXPENSE_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_EXPENSE_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | expense: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_EXPENSE_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_EXPENSE_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_EXPENSE_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_EXPENSE_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'DELETE_EXPENSE_PENDING':
120 | return {
121 | ...state,
122 | fetching: true,
123 | }
124 | case 'DELETE_EXPENSE_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | fetching: false,
129 | fetched: true,
130 | type: 'delete',
131 | message: action.message,
132 | success: true
133 | }
134 |
135 | case 'DELETE_EXPENSE_FAILED':
136 | return {
137 | ...state,
138 | fetching: false,
139 | fetched: true,
140 | error: action.error,
141 | message: action.message,
142 | type: 'delete',
143 | success: false
144 | }
145 |
146 | default:
147 | return state
148 | }
149 | }
150 |
151 | export default expenseReducer
--------------------------------------------------------------------------------
/src/components/DefaultScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { NavLink, Link } from 'react-router-dom'
3 |
4 | class DefaultScreen extends Component {
5 |
6 | handleLogout = () => {
7 | sessionStorage.removeItem('token')
8 | return this.props.history.push('/login')
9 | }
10 |
11 | render() {
12 | const path = this.props.location.pathname.split('/')[1]
13 | const permissions = sessionStorage.getItem('permissions') ? JSON.parse(sessionStorage.getItem('permissions')).filter(permission => permission !== null) : []
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
Kasir Kita 2.0
21 |
22 |
23 | -
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
67 |
68 | {this.props.children}
69 |
70 |
71 |
72 |
73 |
74 | )
75 | }
76 | }
77 |
78 | export default DefaultScreen
79 |
--------------------------------------------------------------------------------
/src/assets/style.css:
--------------------------------------------------------------------------------
1 | .autocomplete-wrapper {
2 | position: relative;
3 | }
4 |
5 | .autocomplete {
6 | position: absolute;
7 | z-index: 2;
8 | background-color: #fff;
9 | width: 100%;
10 | /* border: 1px solid #eee; */
11 | }
12 |
13 | .autocomplete > ul {
14 | padding: 0px;
15 | list-style: none;
16 | }
17 |
18 | .autocomplete > ul > li {
19 | padding: 10px;
20 | border-bottom: 1px solid #eee;
21 | cursor: pointer;
22 | transition: all .2s ease-in-out;
23 | }
24 | .autocomplete > ul > li:hover {
25 | background-color: #007bff;
26 | border-color: #007bff;
27 | color: #fff;
28 | }
29 |
30 | .dropdown-active {
31 | background-color: #007bff;
32 | }
33 |
34 | .dropdown-active > a {
35 | color: #fff;
36 | }
37 |
38 | .table-custom > tbody p {
39 | margin-bottom: 0px;
40 | font-weight: bold;
41 | }
42 |
43 | .table-custom > tbody > tr > td {
44 | font-weight: normal !important;
45 | }
46 |
47 | .table-responsive {
48 | display: table;
49 | }
50 |
51 | .clickable-row {
52 | cursor: pointer;
53 | }
54 |
55 | .table-custom th {
56 | position: relative;
57 | cursor: pointer;
58 | padding-right: 35px !important;
59 | }
60 |
61 | .table-sorting {
62 | position: absolute;
63 | top: 10px;
64 | right: 10px;
65 | color: #ccc;
66 | }
67 |
68 | .table-sorting.active {
69 | color: #007bff;
70 | }
71 |
72 | .table-custom td p {
73 | margin-bottom: 0px !important;
74 | }
75 |
76 | .table-custom td div {
77 | margin-top: 10px;
78 | }
79 |
80 | .table-custom td div button:first-child {
81 | margin-right: 5px;
82 | }
83 |
84 | .table-scrollable tbody{
85 | display:block;
86 | overflow:auto;
87 | height:200px;
88 | width:100%;
89 | }
90 |
91 | .dropzone-wrapper {
92 | border: 2px dashed #eee;
93 | }
94 |
95 | .table-scrollable thead tr, .table-scrollable tfoot tr {
96 | display:block;
97 | }
98 |
99 | .table-scrollable tr > th, .table-scrollable tr > td {
100 | width: 33.3%;
101 | }
102 |
103 | .table-scrollable tr > td {
104 | font-weight: normal;
105 | position: relative;
106 | }
107 |
108 | .table-scrollable tr > td:last-child {
109 | padding-right: 35px;
110 | }
111 |
112 | .table-scrollable tr > td > button.btn-remove {
113 | position: absolute;
114 | right: 0px;
115 | top: 5px;
116 | }
117 |
118 | .table-scrollable-two thead, .table-scrollable tbody tr {
119 | display: table;
120 | width: 100%;
121 | table-layout: fixed;
122 | }
123 |
124 | .table-scrollable-two tbody {
125 | display: block;
126 | overflow-y: scroll;
127 | overflow-x: hidden;
128 | max-height: 150px;
129 | }
130 |
131 | .table-scrollable-two {
132 | display: block;
133 | }
134 |
135 | .table-scrollable-two tfoot {
136 | display: block;
137 | }
138 |
139 | .btn-close-modal {
140 | position: absolute;
141 | right: 0;
142 | }
143 |
144 | .react-datepicker-wrapper {
145 | width: 100% !important;
146 | }
147 |
148 | .receipt {
149 | font-family: monospace;
150 | padding: 10px;
151 | border: 1px solid #aaa;
152 | }
153 |
154 | .term-and-condition {
155 | padding: 20px;
156 | border: 1px solid #e1e1e1;
157 | height: 200px;
158 | overflow-y: scroll;
159 | }
160 |
161 | .btn-disabled {
162 | cursor: not-allowed;
163 | }
164 |
165 | .loading {
166 | position: absolute;
167 | width: 100%;
168 | height: 100vh;
169 | background-color: #fff;
170 | top: 0;
171 | z-index: 2;
172 | color: #ccc;
173 | display: flex;
174 | justify-content: center;
175 | align-items: center;
176 | }
177 |
178 | .pointer {
179 | cursor: pointer;
180 | color: #007bff !important;
181 | }
182 |
183 | .pointer:focus, .pointer[aria-expanded="true"] {
184 | color: #fff !important;
185 | }
186 |
187 | .dropdown-active .pointer {
188 | color: #fff !important;
189 | }
190 |
191 | .uploading {
192 | opacity: .5;
193 | cursor: not-allowed;
194 | }
195 |
196 | .is-invalid-select .css-yk16xz-control {
197 | border-color: hsl(355, 70%, 54%) !important;
198 | }
199 |
200 | .img-avatar {
201 | height: 50px;
202 | object-fit: cover;
203 | }
204 |
205 |
206 | .table-scrollable tbody{
207 | display:block;
208 | overflow:auto;
209 | max-height:200px;
210 | width:100%;
211 | }
212 |
213 | .table-scrollable thead tr, .table-scrollable tfoot tr {
214 | display:block;
215 | }
216 |
217 | .table-scrollable tr > th, .table-scrollable tr > td {
218 | width: 33.3%;
219 | }
220 |
221 | .table-scrollable tr > td {
222 | font-weight: normal;
223 | position: relative;
224 | }
225 |
226 | .table-scrollable tr > td:last-child {
227 | padding-right: 35px;
228 | }
229 |
230 | .table-scrollable tr > td > button.btn-remove {
231 | position: absolute;
232 | right: 0px;
233 | top: 5px;
234 | }
235 |
236 | .table-scrollable tfoot > tr > th {
237 | width: 100%;
238 | }
--------------------------------------------------------------------------------
/src/views/Expense/ViewExpense.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import 'react-datepicker/dist/react-datepicker.css'
3 | import { connect } from 'react-redux'
4 | import { withToastManager } from 'react-toast-notifications'
5 | import { Link } from 'react-router-dom'
6 | import { getExpense } from '../../store/actions/ExpenseActions'
7 |
8 | class ViewExpense extends Component {
9 |
10 | componentDidMount() {
11 | this.props.getExpense(this.props.match.params.id)
12 | }
13 |
14 | render() {
15 | const { expense } = this.props
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
23 |
{ expense && expense.number }
24 |
25 |
26 | Kembali
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | | Nama Toko / Pemasok |
39 | { expense && expense.supplier_name } |
40 | Penanggung Jawab |
41 | { expense && expense.in_charge ? expense.in_charge.name : '-' } |
42 |
43 |
44 | | Tanggal Pembelian |
45 | { expense && expense.payment_date_formatted } |
46 | Di buat oleh |
47 | { expense && expense.user ? expense.user.name : '-'} |
48 |
49 |
50 | | Bukti |
51 | { expense && expense.evidence ? {expense.evidence} : '-' } |
52 | Catatan |
53 | { expense && expense.notes } |
54 |
55 |
56 |
57 |
58 |
59 |
Pembelian
60 |
61 |
62 |
63 | | Nama Barang |
64 | Harga Beli |
65 | Qty |
66 | Total |
67 |
68 |
69 |
70 |
71 | | { expense && expense.product_name} |
72 | { expense && expense.price_formatted} |
73 | { expense && expense.qty} |
74 | { expense && expense.total_formatted} |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | )
84 | }
85 | }
86 |
87 | const mapStateToProps = (state) => {
88 | return {
89 | ...state,
90 | expense: state.expense.expense
91 | }
92 | }
93 |
94 | const mapDispatchToProps = (dispatch) => {
95 | return {
96 | getExpense: id => dispatch(getExpense(id))
97 | }
98 | }
99 |
100 |
101 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(ViewExpense))
102 |
--------------------------------------------------------------------------------
/src/store/actions/SettingActions.js:
--------------------------------------------------------------------------------
1 | import Axios from "axios"
2 | import { url } from "../../global"
3 |
4 | const getSetting = () => {
5 | return (dispatch, getState) => {
6 | dispatch({
7 | type: 'GET_SETTING_PENDING',
8 | })
9 |
10 | Axios.get(`${url}/setting`, {
11 | headers: {
12 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
13 | }
14 | }).then(res => {
15 | dispatch({
16 | type: 'GET_SETTING_SUCCESS',
17 | data: res.data.data,
18 | success: true
19 | })
20 | }).catch(error => {
21 | if (!error.response) {
22 | dispatch({
23 | type: 'GET_SETTING_FAILED',
24 | error: {
25 | status: null,
26 | connection: true,
27 | statusText: 'Koneksi Terputus',
28 | data: {
29 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
30 | }
31 | }
32 | })
33 |
34 | } else {
35 |
36 | dispatch({
37 | type: 'GET_SETTING_FAILED',
38 | error: error.response,
39 | message: error.response.data.message
40 | })
41 | }
42 | })
43 | }
44 | }
45 |
46 | const saveSetting = (data) => {
47 | return (dispatch, getState) => {
48 |
49 | const {
50 | name,
51 | address,
52 | logo,
53 | logo_remove,
54 | phone_number,
55 | divider,
56 | currency,
57 | thousand_separator,
58 | decimal_separator,
59 | tax,
60 | printer
61 | } = data
62 |
63 | dispatch({
64 | type: 'SAVE_SETTING_PENDING'
65 | })
66 |
67 | const fd = new FormData();
68 |
69 | fd.set('name', name)
70 | fd.set('address', address)
71 | fd.append('logo', logo)
72 | fd.set('logo_remove', logo_remove)
73 | fd.set('phone_number', phone_number)
74 | fd.set('divider', divider)
75 | fd.set('currency', currency)
76 | fd.set('thousand_separator', thousand_separator)
77 | fd.set('decimal_separator', decimal_separator)
78 | fd.set('tax', tax)
79 | fd.set('printer', printer)
80 |
81 | Axios.post(`${url}/setting`, fd,
82 | {
83 | headers: {
84 | Authorization: `Bearer ${sessionStorage.getItem('token')}`,
85 | 'Content-Type': 'multipart/form-data'
86 | }
87 | }).then(res => {
88 |
89 | sessionStorage.setItem('decimal_separator', res.data.data.decimal_separator ? res.data.data.decimal_separator : '')
90 | sessionStorage.setItem('thousand_separator', res.data.data.thousand_separator ? res.data.data.thousand_separator : '')
91 | sessionStorage.setItem('currency', res.data.data.currency ? res.data.data.currency : '')
92 | sessionStorage.setItem('printer', res.data.data.printer ? res.data.data.printer : '')
93 | sessionStorage.setItem('tax', res.data.data.tax ? res.data.data.tax : '')
94 | sessionStorage.setItem('logo', res.data.data.logo_url)
95 | sessionStorage.setItem('logo_remove', res.data.data.logo_remove ? res.data.data.logo_remove : false)
96 | sessionStorage.setItem('shop_name', res.data.data.name ? res.data.data.name : '')
97 | sessionStorage.setItem('address', res.data.data.address ? res.data.data.address : '')
98 | sessionStorage.setItem('phone_number', res.data.data.phone_number ? res.data.data.phone_number : '')
99 | sessionStorage.setItem('divider', res.data.data.divider ? res.data.data.divider : '')
100 |
101 |
102 | dispatch({
103 | type: 'SAVE_SETTING_SUCCESS',
104 | data: res.data.data,
105 | message: res.data.message
106 | })
107 |
108 | }).catch(error => {
109 |
110 | if (!error.response) {
111 | dispatch({
112 | type: 'SAVE_SETTING_FAILED',
113 | error: {
114 | status: null,
115 | connection: true,
116 | statusText: 'Koneksi Terputus',
117 | data: {
118 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
119 | }
120 | }
121 | })
122 |
123 | } else {
124 |
125 | dispatch({
126 | type: 'SAVE_SETTING_FAILED',
127 | error: error.response,
128 | message: error.response.data.message
129 | })
130 | }
131 |
132 | })
133 | }
134 | }
135 |
136 |
137 | export { getSetting, saveSetting }
--------------------------------------------------------------------------------
/src/store/reducer/roleReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | role: null,
10 | }
11 |
12 | const roleReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_ROLE_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_ROLE_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_ROLE_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_ROLE_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_ROLE_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_ROLE_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_ROLE_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_ROLE_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | role: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_ROLE_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_ROLE_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_ROLE_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_ROLE_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'TOGGLE_ROLE_PENDING':
120 | return {
121 | ...state,
122 | // fetching: true,
123 | }
124 | case 'TOGGLE_ROLE_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | // fetching: false,
129 | // fetched: true,
130 | // message: action.message,
131 | // type: 'toggle',
132 | // success: true
133 | }
134 |
135 | case 'TOGGLE_ROLE_FAILED':
136 | return {
137 | ...state,
138 | // fetching: false,
139 | // fetched: true,
140 | error: action.error,
141 | // message: action.message,
142 | type: 'toggle',
143 | // success: false
144 | }
145 | case 'DELETE_ROLE_PENDING':
146 | return {
147 | ...state,
148 | fetching: true,
149 | }
150 | case 'DELETE_ROLE_SUCCESS':
151 |
152 | return {
153 | ...state,
154 | fetching: false,
155 | fetched: true,
156 | type: 'delete',
157 | message: action.message,
158 | success: true
159 | }
160 |
161 | case 'DELETE_ROLE_FAILED':
162 | return {
163 | ...state,
164 | fetching: false,
165 | fetched: true,
166 | error: action.error,
167 | message: action.message,
168 | type: 'delete',
169 | success: false
170 | }
171 | default:
172 | return state
173 | }
174 | }
175 |
176 | export default roleReducer
--------------------------------------------------------------------------------
/src/store/reducer/unitReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | unit: null,
10 | }
11 |
12 | const unitReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_UNIT_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_UNIT_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_UNIT_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_UNIT_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_UNIT_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_UNIT_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_UNIT_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_UNIT_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | unit: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_UNIT_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_UNIT_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_UNIT_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_UNIT_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'TOGGLE_UNIT_PENDING':
120 | return {
121 | ...state,
122 | // fetching: true,
123 | }
124 | case 'TOGGLE_UNIT_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | // fetching: false,
129 | // fetched: true,
130 | // message: action.message,
131 | // type: 'toggle',
132 | // success: true
133 | }
134 |
135 | case 'TOGGLE_UNIT_FAILED':
136 | return {
137 | ...state,
138 | // fetching: false,
139 | // fetched: true,
140 | error: action.error,
141 | // message: action.message,
142 | type: 'toggle',
143 | // success: false
144 | }
145 | case 'DELETE_UNIT_PENDING':
146 | return {
147 | ...state,
148 | fetching: true,
149 | }
150 | case 'DELETE_UNIT_SUCCESS':
151 |
152 | return {
153 | ...state,
154 | fetching: false,
155 | fetched: true,
156 | type: 'delete',
157 | message: action.message,
158 | success: true
159 | }
160 |
161 | case 'DELETE_UNIT_FAILED':
162 | return {
163 | ...state,
164 | fetching: false,
165 | fetched: true,
166 | error: action.error,
167 | message: action.message,
168 | type: 'delete',
169 | success: false
170 | }
171 | default:
172 | return state
173 | }
174 | }
175 |
176 | export default unitReducer
--------------------------------------------------------------------------------
/src/store/reducer/userReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | user: null,
10 | }
11 |
12 | const userReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_USER_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_USER_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | selected: action.selected,
29 | type: 'fetch'
30 | }
31 |
32 | case 'FETCH_USER_FAILED':
33 | return {
34 | ...state,
35 | fetching: false,
36 | fetched: true,
37 | error: action.error,
38 | message: action.error.data.message,
39 | success: false,
40 | type: 'fetch'
41 | }
42 | case 'SAVE_USER_PENDING':
43 | return {
44 | ...state,
45 | fetching: true,
46 | }
47 | case 'SAVE_USER_SUCCESS':
48 |
49 | return {
50 | ...state,
51 | fetching: false,
52 | fetched: true,
53 | message: action.message,
54 | type: 'save',
55 | success: true
56 | }
57 |
58 | case 'SAVE_USER_FAILED':
59 | return {
60 | ...state,
61 | fetching: false,
62 | fetched: true,
63 | error: action.error,
64 | message: action.message,
65 | type: 'save',
66 | success: false
67 | }
68 | case 'GET_USER_PENDING':
69 | return {
70 | ...state,
71 | fetching: true,
72 | }
73 | case 'GET_USER_SUCCESS':
74 |
75 | return {
76 | ...state,
77 | fetching: false,
78 | fetched: true,
79 | type: 'get',
80 | user: action.data,
81 | success: true
82 | }
83 |
84 | case 'GET_USER_FAILED':
85 | return {
86 | ...state,
87 | fetching: false,
88 | fetched: true,
89 | error: action.error,
90 | message: action.message,
91 | type: 'get',
92 | success: false
93 | }
94 | case 'UPDATE_USER_PENDING':
95 | return {
96 | ...state,
97 | fetching: true,
98 | }
99 | case 'UPDATE_USER_SUCCESS':
100 |
101 | return {
102 | ...state,
103 | fetching: false,
104 | fetched: true,
105 | message: action.message,
106 | type: 'update',
107 | success: true
108 | }
109 |
110 | case 'UPDATE_USER_FAILED':
111 | return {
112 | ...state,
113 | fetching: false,
114 | fetched: true,
115 | error: action.error,
116 | message: action.message,
117 | type: 'update',
118 | success: false
119 | }
120 | case 'TOGGLE_USER_PENDING':
121 | return {
122 | ...state,
123 | // fetching: true,
124 | }
125 | case 'TOGGLE_USER_SUCCESS':
126 |
127 | return {
128 | ...state,
129 | // fetching: false,
130 | // fetched: true,
131 | // message: action.message,
132 | // type: 'toggle',
133 | // success: true
134 | }
135 |
136 | case 'TOGGLE_USER_FAILED':
137 | return {
138 | ...state,
139 | // fetching: false,
140 | // fetched: true,
141 | error: action.error,
142 | // message: action.message,
143 | type: 'toggle',
144 | // success: false
145 | }
146 | case 'DELETE_USER_PENDING':
147 | return {
148 | ...state,
149 | fetching: true,
150 | }
151 | case 'DELETE_USER_SUCCESS':
152 |
153 | return {
154 | ...state,
155 | fetching: false,
156 | fetched: true,
157 | type: 'delete',
158 | message: action.message,
159 | success: true
160 | }
161 |
162 | case 'DELETE_USER_FAILED':
163 | return {
164 | ...state,
165 | fetching: false,
166 | fetched: true,
167 | error: action.error,
168 | message: action.message,
169 | type: 'delete',
170 | success: false
171 | }
172 |
173 | default:
174 | return state
175 | }
176 | }
177 |
178 | export default userReducer
--------------------------------------------------------------------------------
/src/store/reducer/salesReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | sales: null,
10 | carts: null
11 | }
12 |
13 | const salesReducer = (state = initState, action) => {
14 | switch (action.type) {
15 | case 'FETCH_SALES_PENDING':
16 | return {
17 | ...state,
18 | fetching: true,
19 | error: null
20 | }
21 | case 'FETCH_SALES_SUCCESS':
22 |
23 | return {
24 | ...state,
25 | fetching: false,
26 | fetched: true,
27 | data: action.data,
28 | success: true,
29 | type: 'fetch'
30 | }
31 |
32 | case 'FETCH_SALES_FAILED':
33 | return {
34 | ...state,
35 | fetching: false,
36 | fetched: true,
37 | error: action.error,
38 | message: action.error.data.message,
39 | success: false,
40 | type: 'fetch'
41 | }
42 | case 'SAVE_SALES_PENDING':
43 | return {
44 | ...state,
45 | fetching: true,
46 | }
47 | case 'SAVE_SALES_SUCCESS':
48 |
49 | return {
50 | ...state,
51 | fetching: false,
52 | fetched: true,
53 | message: action.message,
54 | carts: action.data,
55 | type: 'save',
56 | success: true
57 | }
58 |
59 | case 'SAVE_SALES_FAILED':
60 | return {
61 | ...state,
62 | fetching: false,
63 | fetched: true,
64 | error: action.error,
65 | message: action.message,
66 | type: 'save',
67 | success: false
68 | }
69 | case 'GET_SALES_PENDING':
70 | return {
71 | ...state,
72 | fetching: true,
73 | }
74 | case 'GET_SALES_SUCCESS':
75 |
76 | return {
77 | ...state,
78 | fetching: false,
79 | fetched: true,
80 | type: 'get',
81 | sales: action.data,
82 | success: true
83 | }
84 |
85 | case 'GET_SALES_FAILED':
86 | return {
87 | ...state,
88 | fetching: false,
89 | fetched: true,
90 | error: action.error,
91 | message: action.message,
92 | type: 'get',
93 | success: false
94 | }
95 | case 'UPDATE_SALES_PENDING':
96 | return {
97 | ...state,
98 | fetching: true,
99 | }
100 | case 'UPDATE_SALES_SUCCESS':
101 |
102 | return {
103 | ...state,
104 | fetching: false,
105 | fetched: true,
106 | message: action.message,
107 | type: 'update',
108 | success: true
109 | }
110 |
111 | case 'UPDATE_SALES_FAILED':
112 | return {
113 | ...state,
114 | fetching: false,
115 | fetched: true,
116 | error: action.error,
117 | message: action.message,
118 | type: 'update',
119 | success: false
120 | }
121 | case 'TOGGLE_SALES_PENDING':
122 | return {
123 | ...state,
124 | // fetching: true,
125 | }
126 | case 'TOGGLE_SALES_SUCCESS':
127 |
128 | return {
129 | ...state,
130 | // fetching: false,
131 | // fetched: true,
132 | // message: action.message,
133 | // type: 'toggle',
134 | // success: true
135 | }
136 |
137 | case 'TOGGLE_SALES_FAILED':
138 | return {
139 | ...state,
140 | // fetching: false,
141 | // fetched: true,
142 | error: action.error,
143 | // message: action.message,
144 | type: 'toggle',
145 | // success: false
146 | }
147 | case 'DELETE_SALES_PENDING':
148 | return {
149 | ...state,
150 | fetching: true,
151 | }
152 | case 'DELETE_SALES_SUCCESS':
153 |
154 | return {
155 | ...state,
156 | fetching: false,
157 | fetched: true,
158 | type: 'delete',
159 | message: action.message,
160 | success: true
161 | }
162 |
163 | case 'DELETE_SALES_FAILED':
164 | return {
165 | ...state,
166 | fetching: false,
167 | fetched: true,
168 | error: action.error,
169 | message: action.message,
170 | type: 'delete',
171 | success: false
172 | }
173 | default:
174 | return state
175 | }
176 | }
177 |
178 | export default salesReducer
--------------------------------------------------------------------------------
/src/store/reducer/categoryReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | category: null,
10 | }
11 |
12 | const categoryReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_CATEGORY_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_CATEGORY_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_CATEGORY_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_CATEGORY_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_CATEGORY_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_CATEGORY_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_CATEGORY_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_CATEGORY_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | category: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_CATEGORY_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_CATEGORY_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_CATEGORY_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_CATEGORY_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'TOGGLE_CATEGORY_PENDING':
120 | return {
121 | ...state,
122 | // fetching: true,
123 | }
124 | case 'TOGGLE_CATEGORY_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | // fetching: false,
129 | // fetched: true,
130 | // message: action.message,
131 | // type: 'toggle',
132 | // success: true
133 | }
134 |
135 | case 'TOGGLE_CATEGORY_FAILED':
136 | return {
137 | ...state,
138 | // fetching: false,
139 | // fetched: true,
140 | error: action.error,
141 | // message: action.message,
142 | type: 'toggle',
143 | // success: false
144 | }
145 | case 'DELETE_CATEGORY_PENDING':
146 | return {
147 | ...state,
148 | fetching: true,
149 | }
150 | case 'DELETE_CATEGORY_SUCCESS':
151 |
152 | return {
153 | ...state,
154 | fetching: false,
155 | fetched: true,
156 | type: 'delete',
157 | message: action.message,
158 | success: true
159 | }
160 |
161 | case 'DELETE_CATEGORY_FAILED':
162 | return {
163 | ...state,
164 | fetching: false,
165 | fetched: true,
166 | error: action.error,
167 | message: action.message,
168 | type: 'delete',
169 | success: false
170 | }
171 | default:
172 | return state
173 | }
174 | }
175 |
176 | export default categoryReducer
--------------------------------------------------------------------------------
/src/store/reducer/customerReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | customer: null
10 | }
11 |
12 | const customerReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_CUSTOMER_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_CUSTOMER_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_CUSTOMER_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_CUSTOMER_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_CUSTOMER_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_CUSTOMER_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_CUSTOMER_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_CUSTOMER_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | customer: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_CUSTOMER_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_CUSTOMER_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_CUSTOMER_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_CUSTOMER_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'TOGGLE_CUSTOMER_PENDING':
120 | return {
121 | ...state,
122 | // fetching: true,
123 | }
124 | case 'TOGGLE_CUSTOMER_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | // fetching: false,
129 | // fetched: true,
130 | // message: action.message,
131 | // type: 'toggle',
132 | // success: true
133 | }
134 |
135 | case 'TOGGLE_CUSTOMER_FAILED':
136 | return {
137 | ...state,
138 | // fetching: false,
139 | // fetched: true,
140 | error: action.error,
141 | // message: action.message,
142 | type: 'toggle',
143 | // success: false
144 | }
145 | case 'DELETE_CUSTOMER_PENDING':
146 | return {
147 | ...state,
148 | fetching: true,
149 | }
150 | case 'DELETE_CUSTOMER_SUCCESS':
151 |
152 | return {
153 | ...state,
154 | fetching: false,
155 | fetched: true,
156 | type: 'delete',
157 | message: action.message,
158 | success: true
159 | }
160 |
161 | case 'DELETE_CUSTOMER_FAILED':
162 | return {
163 | ...state,
164 | fetching: false,
165 | fetched: true,
166 | error: action.error,
167 | message: action.message,
168 | type: 'delete',
169 | success: false
170 | }
171 | default:
172 | return state
173 | }
174 | }
175 |
176 | export default customerReducer
--------------------------------------------------------------------------------
/src/store/reducer/supplierReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | supplier: null
10 | }
11 |
12 | const supplierReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_SUPPLIER_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_SUPPLIER_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | type: 'fetch'
29 | }
30 |
31 | case 'FETCH_SUPPLIER_FAILED':
32 | return {
33 | ...state,
34 | fetching: false,
35 | fetched: true,
36 | error: action.error,
37 | message: action.error.data.message,
38 | success: false,
39 | type: 'fetch'
40 | }
41 | case 'SAVE_SUPPLIER_PENDING':
42 | return {
43 | ...state,
44 | fetching: true,
45 | }
46 | case 'SAVE_SUPPLIER_SUCCESS':
47 |
48 | return {
49 | ...state,
50 | fetching: false,
51 | fetched: true,
52 | message: action.message,
53 | type: 'save',
54 | success: true
55 | }
56 |
57 | case 'SAVE_SUPPLIER_FAILED':
58 | return {
59 | ...state,
60 | fetching: false,
61 | fetched: true,
62 | error: action.error,
63 | message: action.message,
64 | type: 'save',
65 | success: false
66 | }
67 | case 'GET_SUPPLIER_PENDING':
68 | return {
69 | ...state,
70 | fetching: true,
71 | }
72 | case 'GET_SUPPLIER_SUCCESS':
73 |
74 | return {
75 | ...state,
76 | fetching: false,
77 | fetched: true,
78 | type: 'get',
79 | supplier: action.data,
80 | success: true
81 | }
82 |
83 | case 'GET_SUPPLIER_FAILED':
84 | return {
85 | ...state,
86 | fetching: false,
87 | fetched: true,
88 | error: action.error,
89 | message: action.message,
90 | type: 'get',
91 | success: false
92 | }
93 | case 'UPDATE_SUPPLIER_PENDING':
94 | return {
95 | ...state,
96 | fetching: true,
97 | }
98 | case 'UPDATE_SUPPLIER_SUCCESS':
99 |
100 | return {
101 | ...state,
102 | fetching: false,
103 | fetched: true,
104 | message: action.message,
105 | type: 'update',
106 | success: true
107 | }
108 |
109 | case 'UPDATE_SUPPLIER_FAILED':
110 | return {
111 | ...state,
112 | fetching: false,
113 | fetched: true,
114 | error: action.error,
115 | message: action.message,
116 | type: 'update',
117 | success: false
118 | }
119 | case 'TOGGLE_SUPPLIER_PENDING':
120 | return {
121 | ...state,
122 | // fetching: true,
123 | }
124 | case 'TOGGLE_SUPPLIER_SUCCESS':
125 |
126 | return {
127 | ...state,
128 | // fetching: false,
129 | // fetched: true,
130 | // message: action.message,
131 | // type: 'toggle',
132 | // success: true
133 | }
134 |
135 | case 'TOGGLE_SUPPLIER_FAILED':
136 | return {
137 | ...state,
138 | // fetching: false,
139 | // fetched: true,
140 | error: action.error,
141 | // message: action.message,
142 | type: 'toggle',
143 | // success: false
144 | }
145 | case 'DELETE_SUPPLIER_PENDING':
146 | return {
147 | ...state,
148 | fetching: true,
149 | }
150 | case 'DELETE_SUPPLIER_SUCCESS':
151 |
152 | return {
153 | ...state,
154 | fetching: false,
155 | fetched: true,
156 | type: 'delete',
157 | message: action.message,
158 | success: true
159 | }
160 |
161 | case 'DELETE_SUPPLIER_FAILED':
162 | return {
163 | ...state,
164 | fetching: false,
165 | fetched: true,
166 | error: action.error,
167 | message: action.message,
168 | type: 'delete',
169 | success: false
170 | }
171 | default:
172 | return state
173 | }
174 | }
175 |
176 | export default supplierReducer
--------------------------------------------------------------------------------
/src/store/reducer/purchaseReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | purchase: null,
10 | }
11 |
12 | const purchaseReducer = (state = initState, action) => {
13 | switch (action.type) {
14 | case 'FETCH_PURCHASE_PENDING':
15 | return {
16 | ...state,
17 | fetching: true,
18 | error: null
19 | }
20 | case 'FETCH_PURCHASE_SUCCESS':
21 |
22 | return {
23 | ...state,
24 | fetching: false,
25 | fetched: true,
26 | data: action.data,
27 | success: true,
28 | selected: action.selected,
29 | type: 'fetch'
30 | }
31 |
32 | case 'FETCH_PURCHASE_FAILED':
33 | return {
34 | ...state,
35 | fetching: false,
36 | fetched: true,
37 | error: action.error,
38 | message: action.error.data.message,
39 | success: false,
40 | type: 'fetch'
41 | }
42 | case 'SAVE_PURCHASE_PENDING':
43 | return {
44 | ...state,
45 | fetching: true,
46 | }
47 | case 'SAVE_PURCHASE_SUCCESS':
48 |
49 | return {
50 | ...state,
51 | fetching: false,
52 | fetched: true,
53 | message: action.message,
54 | type: 'save',
55 | success: true
56 | }
57 |
58 | case 'SAVE_PURCHASE_FAILED':
59 | return {
60 | ...state,
61 | fetching: false,
62 | fetched: true,
63 | error: action.error,
64 | message: action.message,
65 | type: 'save',
66 | success: false
67 | }
68 | case 'GET_PURCHASE_PENDING':
69 | return {
70 | ...state,
71 | fetching: true,
72 | }
73 | case 'GET_PURCHASE_SUCCESS':
74 |
75 | return {
76 | ...state,
77 | fetching: false,
78 | fetched: true,
79 | type: 'get',
80 | purchase: action.data,
81 | success: true
82 | }
83 |
84 | case 'GET_PURCHASE_FAILED':
85 | return {
86 | ...state,
87 | fetching: false,
88 | fetched: true,
89 | error: action.error,
90 | message: action.message,
91 | type: 'get',
92 | success: false
93 | }
94 | case 'UPDATE_PURCHASE_PENDING':
95 | return {
96 | ...state,
97 | fetching: true,
98 | }
99 | case 'UPDATE_PURCHASE_SUCCESS':
100 |
101 | return {
102 | ...state,
103 | fetching: false,
104 | fetched: true,
105 | message: action.message,
106 | type: 'update',
107 | success: true
108 | }
109 |
110 | case 'UPDATE_PURCHASE_FAILED':
111 | return {
112 | ...state,
113 | fetching: false,
114 | fetched: true,
115 | error: action.error,
116 | message: action.message,
117 | type: 'update',
118 | success: false
119 | }
120 | case 'TOGGLE_PURCHASE_PENDING':
121 | return {
122 | ...state,
123 | // fetching: true,
124 | }
125 | case 'TOGGLE_PURCHASE_SUCCESS':
126 |
127 | return {
128 | ...state,
129 | // fetching: false,
130 | // fetched: true,
131 | // message: action.message,
132 | // type: 'toggle',
133 | // success: true
134 | }
135 |
136 | case 'TOGGLE_PURCHASE_FAILED':
137 | return {
138 | ...state,
139 | // fetching: false,
140 | // fetched: true,
141 | error: action.error,
142 | // message: action.message,
143 | type: 'toggle',
144 | // success: false
145 | }
146 | case 'DELETE_PURCHASE_PENDING':
147 | return {
148 | ...state,
149 | fetching: true,
150 | }
151 | case 'DELETE_PURCHASE_SUCCESS':
152 |
153 | return {
154 | ...state,
155 | fetching: false,
156 | fetched: true,
157 | type: 'delete',
158 | message: action.message,
159 | success: true
160 | }
161 |
162 | case 'DELETE_PURCHASE_FAILED':
163 | return {
164 | ...state,
165 | fetching: false,
166 | fetched: true,
167 | error: action.error,
168 | message: action.message,
169 | type: 'delete',
170 | success: false
171 | }
172 |
173 | default:
174 | return state
175 | }
176 | }
177 |
178 | export default purchaseReducer
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' }
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready.then(registration => {
134 | registration.unregister();
135 | });
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/store/reducer/discountReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | discount: null,
10 | selected: null
11 | }
12 |
13 | const discountReducer = (state = initState, action) => {
14 | switch (action.type) {
15 | case 'FETCH_DISCOUNT_PENDING':
16 | return {
17 | ...state,
18 | fetching: true,
19 | error: null
20 | }
21 | case 'FETCH_DISCOUNT_SUCCESS':
22 |
23 | return {
24 | ...state,
25 | fetching: false,
26 | fetched: true,
27 | data: action.data,
28 | selected: action.selected,
29 | success: true,
30 | type: 'fetch'
31 | }
32 |
33 | case 'FETCH_DISCOUNT_FAILED':
34 | return {
35 | ...state,
36 | fetching: false,
37 | fetched: true,
38 | error: action.error,
39 | message: action.error.data.message,
40 | success: false,
41 | type: 'fetch'
42 | }
43 | case 'SAVE_DISCOUNT_PENDING':
44 | return {
45 | ...state,
46 | fetching: true,
47 | }
48 | case 'SAVE_DISCOUNT_SUCCESS':
49 |
50 | return {
51 | ...state,
52 | fetching: false,
53 | fetched: true,
54 | message: action.message,
55 | type: 'save',
56 | success: true
57 | }
58 |
59 | case 'SAVE_DISCOUNT_FAILED':
60 | return {
61 | ...state,
62 | fetching: false,
63 | fetched: true,
64 | error: action.error,
65 | message: action.message,
66 | type: 'save',
67 | success: false
68 | }
69 | case 'GET_DISCOUNT_PENDING':
70 | return {
71 | ...state,
72 | fetching: true,
73 | }
74 | case 'GET_DISCOUNT_SUCCESS':
75 |
76 | return {
77 | ...state,
78 | fetching: false,
79 | fetched: true,
80 | type: 'get',
81 | discount: action.data,
82 | success: true
83 | }
84 |
85 | case 'GET_DISCOUNT_FAILED':
86 | return {
87 | ...state,
88 | fetching: false,
89 | fetched: true,
90 | error: action.error,
91 | message: action.message,
92 | type: 'get',
93 | success: false
94 | }
95 | case 'UPDATE_DISCOUNT_PENDING':
96 | return {
97 | ...state,
98 | fetching: true,
99 | }
100 | case 'UPDATE_DISCOUNT_SUCCESS':
101 |
102 | return {
103 | ...state,
104 | fetching: false,
105 | fetched: true,
106 | message: action.message,
107 | type: 'update',
108 | success: true
109 | }
110 |
111 | case 'UPDATE_DISCOUNT_FAILED':
112 | return {
113 | ...state,
114 | fetching: false,
115 | fetched: true,
116 | error: action.error,
117 | message: action.message,
118 | type: 'update',
119 | success: false
120 | }
121 | case 'TOGGLE_DISCOUNT_PENDING':
122 | return {
123 | ...state,
124 | // fetching: true,
125 | }
126 | case 'TOGGLE_DISCOUNT_SUCCESS':
127 |
128 | return {
129 | ...state,
130 | // fetching: false,
131 | // fetched: true,
132 | // message: action.message,
133 | // type: 'toggle',
134 | // success: true
135 | }
136 |
137 | case 'TOGGLE_DISCOUNT_FAILED':
138 | return {
139 | ...state,
140 | // fetching: false,
141 | // fetched: true,
142 | error: action.error,
143 | // message: action.message,
144 | type: 'toggle',
145 | // success: false
146 | }
147 | case 'DELETE_DISCOUNT_PENDING':
148 | return {
149 | ...state,
150 | fetching: true,
151 | }
152 | case 'DELETE_DISCOUNT_SUCCESS':
153 |
154 | return {
155 | ...state,
156 | fetching: false,
157 | fetched: true,
158 | type: 'delete',
159 | message: action.message,
160 | success: true
161 | }
162 |
163 | case 'DELETE_DISCOUNT_FAILED':
164 | return {
165 | ...state,
166 | fetching: false,
167 | fetched: true,
168 | error: action.error,
169 | message: action.message,
170 | type: 'delete',
171 | success: false
172 | }
173 | case 'SELECT_DISCOUNT_PENDING':
174 | return {
175 | ...state,
176 | // fetching: true,
177 | }
178 | case 'SELECT_DISCOUNT_SUCCESS':
179 |
180 | return {
181 | ...state,
182 | selected: action.selected
183 | // fetching: false,
184 | // fetched: true,
185 | // message: action.message,
186 | // type: 'toggle',
187 | // success: true
188 | }
189 |
190 | case 'SELECT_DISCOUNT_FAILED':
191 | return {
192 | ...state,
193 | // fetching: false,
194 | // fetched: true,
195 | error: action.error,
196 | // message: action.message,
197 | type: 'toggle',
198 | // success: false
199 | }
200 | default:
201 | return state
202 | }
203 | }
204 |
205 | export default discountReducer
--------------------------------------------------------------------------------
/src/views/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { checkUser, login } from '../store/actions/AuthActions'
3 | import { connect } from 'react-redux'
4 | import Error from './Errors/Error'
5 | import Loading from '../components/Loading'
6 | import { withToastManager } from 'react-toast-notifications'
7 |
8 | class Login extends Component {
9 |
10 | state = {
11 | agree: false,
12 | email: 'aplikasikasirkita@gmail.com',
13 | password: 'secret'
14 | }
15 |
16 | componentDidMount = () => {
17 | this.props.checkUser()
18 | }
19 |
20 | componentDidUpdate = (prevProps) => {
21 | const { toastManager } = this.props;
22 |
23 | if (prevProps.checkUserExists !== this.props.checkUserExists) {
24 | if (!this.props.checkUserExists)
25 | return this.props.history.push('/welcome')
26 | }
27 |
28 | if (prevProps.loginFetching !== this.props.loginFetching ) {
29 |
30 |
31 | if (this.props.loginFetched) {
32 |
33 | if (this.props.loginSuccess) {
34 |
35 | toastManager.add(this.props.loginMessage, {
36 | appearance: 'success',
37 | autoDismiss: true
38 | });
39 |
40 | return this.props.history.push(this.props.loginRedirect)
41 |
42 | } else {
43 |
44 | toastManager.add(this.props.loginMessage, {
45 | appearance: 'error',
46 | autoDismiss: true
47 | });
48 | }
49 |
50 |
51 | }
52 | }
53 | }
54 |
55 |
56 | handleChange = (name) => (e) => {
57 | this.setState({
58 | ...this.state,
59 | [name]: e.target.value
60 | })
61 | }
62 |
63 | handleSubmit = (e) => {
64 | e.preventDefault()
65 | this.props.login(this.state)
66 | }
67 |
68 | handleReset = () => {
69 | this.setState({
70 | agree: false,
71 | email: '',
72 | password: ''
73 | })
74 | }
75 |
76 | render() {
77 |
78 | const {
79 | checkFetching,
80 | checkError,
81 | loginFetching,
82 | loginError
83 |
84 | } = this.props
85 |
86 | const { email, password } = this.state
87 |
88 | const error = loginError && loginError.data && loginError.data.errors
89 |
90 | if (checkError && checkError.status !== 422)
91 | return
92 |
93 | return (
94 |
95 | {
96 | checkFetching && (
97 |
98 | )
99 | }
100 |
101 |
Masuk
102 |
Silahkan masukan username dan password
103 |
135 |
136 |
137 | )
138 | }
139 | }
140 |
141 | const mapStateToProps = (state) => {
142 | return {
143 | checkFetching: state.checkUser.fetching,
144 | checkFetched: state.checkUser.fetched,
145 | checkUserExists: state.checkUser.userExists,
146 | checkError: state.checkUser.error,
147 | loginFetching: state.login.fetching,
148 | loginFetched: state.login.fetched,
149 | loginMessage: state.login.message,
150 | loginError: state.login.error,
151 | loginSuccess: state.login.success,
152 | loginRedirect: state.login.redirect
153 | }
154 | }
155 |
156 | const mapDispatchToProps = (dispatch) => {
157 | return {
158 | checkUser: () => dispatch(checkUser()),
159 | login: (data) => dispatch(login(data))
160 | }
161 | }
162 |
163 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(Login))
164 |
--------------------------------------------------------------------------------
/src/store/actions/AuthActions.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios'
2 | import { url } from '../../global'
3 |
4 | const checkUser = () => {
5 | return (dispatch, getState) => {
6 |
7 | dispatch({
8 | type: 'CHECK_USER_PENDING'
9 | })
10 |
11 | Axios.get(`${url}/check`).then(res => {
12 | dispatch({
13 | type: 'CHECK_USER_SUCCESS',
14 | userExists: res.data.user_exists
15 | })
16 | }).catch(error => {
17 |
18 | if (!error.response) {
19 | dispatch({
20 | type: 'CHECK_USER_FAILED',
21 | error: {
22 | status: null,
23 | connection: true,
24 | statusText: 'Koneksi Terputus',
25 | data: {
26 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
27 | }
28 | }
29 | })
30 |
31 | } else {
32 |
33 | dispatch({
34 | type: 'CHECK_USER_FAILED',
35 | error: error.response
36 | })
37 | }
38 |
39 | })
40 | }
41 | }
42 |
43 | const register = (data) => {
44 | return async (dispatch, getState) => {
45 |
46 | const {
47 | name,
48 | email,
49 | password,
50 | password_confirmation
51 | } = data
52 |
53 | dispatch({
54 | type: 'REGISTER_PENDING'
55 | })
56 |
57 | await Axios.post(`${url}/register`, {
58 |
59 | name,
60 | email,
61 | password,
62 | password_confirmation
63 |
64 | }).then(res => {
65 |
66 | const setting = res.data.setting
67 | sessionStorage.setItem('decimal_separator', setting ? setting.decimal_separator : '.')
68 | sessionStorage.setItem('thousand_separator', setting ? setting.thousand_separator : '.' )
69 | sessionStorage.setItem('currency', setting ? setting.currency : '')
70 | sessionStorage.setItem('printer', setting ? setting.printer : '')
71 | sessionStorage.setItem('tax', setting ? setting.tax : '')
72 | sessionStorage.setItem('logo', setting.logo_url)
73 | sessionStorage.setItem('logo_remove', setting.logo_remove ? setting.logo_remove : false)
74 | sessionStorage.setItem('shop_name', setting.name ? setting.name : '')
75 | sessionStorage.setItem('address', setting.address ? setting.address : '')
76 | sessionStorage.setItem('phone_number', setting.phone_number ? setting.phone_number : '')
77 | sessionStorage.setItem('divider', setting.divider ? setting.divider : '')
78 |
79 |
80 | dispatch({
81 | type: 'REGISTER_SUCCESS',
82 | token: res.data.token,
83 | data: res.data.data,
84 | message: res.data.message
85 | })
86 | }).catch(error => {
87 | if (!error.response) {
88 | dispatch({
89 | type: 'REGISTER_FAILED',
90 | error: {
91 | status: null,
92 | connection: true,
93 | statusText: 'Koneksi Terputus',
94 | data: {
95 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
96 | }
97 | }
98 | })
99 |
100 | } else {
101 |
102 | dispatch({
103 | type: 'REGISTER_FAILED',
104 | error: error.response
105 | })
106 | }
107 | })
108 | }
109 | }
110 |
111 |
112 | const login = (data) => {
113 | return (dispatch, getState) => {
114 |
115 | const {
116 | email,
117 | password
118 | } = data
119 |
120 | dispatch({
121 | type: 'LOGIN_PENDING'
122 | })
123 |
124 | Axios.post(`${url}/login`, {
125 | email,
126 | password
127 |
128 | }).then(res => {
129 |
130 | const setting = res.data.setting
131 | sessionStorage.setItem('decimal_separator', setting ? setting.decimal_separator : '.')
132 | sessionStorage.setItem('thousand_separator', setting ? setting.thousand_separator : '.' )
133 | sessionStorage.setItem('currency', setting ? setting.currency : '')
134 | sessionStorage.setItem('printer', setting ? setting.printer : '')
135 | sessionStorage.setItem('tax', setting ? setting.tax : '')
136 | sessionStorage.setItem('logo', setting.logo_url)
137 | sessionStorage.setItem('logo_remove', setting.logo_remove ? setting.logo_remove : false)
138 | sessionStorage.setItem('shop_name', setting.name ? setting.name : '')
139 | sessionStorage.setItem('address', setting.address ? setting.address : '')
140 | sessionStorage.setItem('phone_number', setting.phone_number ? setting.phone_number : '')
141 | sessionStorage.setItem('divider', setting.divider ? setting.divider : '')
142 |
143 | dispatch({
144 | type: 'LOGIN_SUCCESS',
145 | token: res.data.token,
146 | data: res.data.data,
147 | message: res.data.message,
148 | permissions: res.data.permissions,
149 | redirect: res.data.redirect
150 | })
151 | }).catch(error => {
152 | if (!error.response) {
153 | dispatch({
154 | type: 'LOGIN_FAILED',
155 | error: {
156 | status: null,
157 | connection: true,
158 | statusText: 'Koneksi Terputus',
159 | data: {
160 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
161 | }
162 | }
163 | })
164 |
165 | } else {
166 |
167 | dispatch({
168 | type: 'LOGIN_FAILED',
169 | error: error.response
170 | })
171 | }
172 | })
173 | }
174 | }
175 |
176 | export { checkUser, register, login }
--------------------------------------------------------------------------------
/src/views/Supplier/AddSupplier.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { saveSupplier } from '../../store/actions/SupplierActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import Error from '../Errors/Error'
7 |
8 | class AddSupplier extends Component {
9 |
10 | state = {
11 | name: '',
12 | email: '',
13 | phone_number: '',
14 | address: ''
15 | }
16 |
17 | handleSave = () => {
18 | this.props.saveSupplier(this.state)
19 | }
20 |
21 | handleReset = () => {
22 |
23 | this.setState({
24 | name: '',
25 | email: '',
26 | phone_number: '',
27 | address: ''
28 | })
29 | }
30 |
31 | handleChange = (name) => (e) => {
32 | this.setState({
33 | ...this.state,
34 | [name]: e.target.value
35 | })
36 | }
37 |
38 | componentDidUpdate = (prevProps) => {
39 |
40 | const { toastManager } = this.props;
41 |
42 | if (prevProps.type !== this.props.type || prevProps.success !== this.props.success) {
43 | if (this.props.type === 'save') {
44 |
45 | if (this.props.success) {
46 |
47 | toastManager.add(this.props.message, {
48 | appearance: 'success',
49 | autoDismiss: true
50 | });
51 |
52 | return this.props.history.push('/suppler')
53 |
54 | } else {
55 |
56 | toastManager.add(this.props.message, {
57 | appearance: 'error',
58 | autoDismiss: true
59 | });
60 | }
61 | }
62 | }
63 | }
64 |
65 |
66 | render() {
67 |
68 | const { error, fetching } = this.props
69 |
70 | const {
71 | name,
72 | email,
73 | phone_number,
74 | address
75 | } = this.state
76 |
77 | const validate = error && error.data && error.data.errors
78 |
79 | if (error && error.status !== 422)
80 | return
81 |
82 | return (
83 |
84 |
85 |
86 |
87 |
88 |
89 |
Tambah Pemasok
90 |
91 |
92 | Kembali
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | {
104 | validate && validate.name && (
105 |
{ validate.name[0] }
106 | )
107 | }
108 |
109 |
110 |
111 |
112 |
113 |
114 | {
115 | validate && validate.email && (
116 |
{ validate.email[0] }
117 | )
118 | }
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | {
140 | fetching ? (
141 |
142 | ) : (
143 |
144 | )
145 | }
146 |
147 |
148 |
149 | )
150 | }
151 | }
152 |
153 | const mapStateToProps = state => {
154 | return {
155 | ...state,
156 | message: state.supplier.message,
157 | fetching: state.supplier.fetching,
158 | error: state.supplier.error,
159 | success: state.supplier.success,
160 | type: state.supplier.type
161 | }
162 | }
163 |
164 | const mapDispatchToProps = dispatch => {
165 | return {
166 | saveSupplier: data => dispatch(saveSupplier(data))
167 | }
168 | }
169 |
170 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(AddSupplier))
--------------------------------------------------------------------------------
/src/views/Role/AddRole.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { saveRole } from '../../store/actions/RoleActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import Error from '../Errors/Error'
7 | import { getListPermission } from '../../store/actions/PermissionAction'
8 |
9 | class AddRole extends Component {
10 |
11 | state = {
12 | name: '',
13 | permissions: {}
14 | }
15 |
16 | handleChange = (name) => (e) => {
17 | this.setState({
18 | ...this.state,
19 | [name]: e.target.value
20 | })
21 | }
22 |
23 | handleSubmit = (e) => {
24 | e.preventDefault()
25 | this.props.saveRole(this.state)
26 | }
27 |
28 | handleClickCheckbox = (e) => {
29 | const { permissions } = this.state
30 | this.setState({
31 | ...this.state,
32 | permissions: {
33 | ...permissions,
34 | [e.target.value]: e.target.checked
35 | }
36 | })
37 | }
38 |
39 | componentDidUpdate = (prevProps) => {
40 |
41 | if (prevProps.type !== this.props.type || prevProps.success !== this.props.success) {
42 | if (this.props.type === 'save') {
43 | const { toastManager } = this.props;
44 |
45 | if (this.props.success) {
46 |
47 | toastManager.add(this.props.message, {
48 | appearance: 'success',
49 | autoDismiss: true
50 | });
51 |
52 | return this.props.history.push('/role')
53 |
54 | } else {
55 |
56 | toastManager.add(this.props.message, {
57 | appearance: 'error',
58 | autoDismiss: true
59 | });
60 | }
61 | }
62 | }
63 | }
64 |
65 | componentDidMount() {
66 | this.props.getListPermission()
67 | }
68 |
69 | render() {
70 |
71 | const { error, permissions } = this.props
72 | const validate = error && error.data && error.data.errors
73 |
74 | if (error && error.status !== 422)
75 | return
76 |
77 | return (
78 |
79 |
134 |
135 | )
136 | }
137 | }
138 |
139 | const mapStateToProps = state => {
140 | return {
141 | ...state,
142 | message: state.role.message,
143 | fetching: state.role.fetching,
144 | error: state.role.error,
145 | success: state.role.success,
146 | type: state.role.type,
147 | permissions: state.permission.permissions
148 | }
149 | }
150 |
151 | const mapDispatchToProps = dispatch => {
152 | return {
153 | saveRole: data => dispatch(saveRole(data)),
154 | getListPermission: () => dispatch(getListPermission())
155 | }
156 | }
157 |
158 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(AddRole))
159 |
--------------------------------------------------------------------------------
/src/store/reducer/productReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | fetching: false,
3 | fetched: false,
4 | message: null,
5 | data: null,
6 | error: null,
7 | success: null,
8 | type: null,
9 | product: null,
10 | selected: null
11 | }
12 |
13 | const productReducer = (state = initState, action) => {
14 | switch (action.type) {
15 | case 'FETCH_PRODUCT_PENDING':
16 | return {
17 | ...state,
18 | fetching: true,
19 | error: null
20 | }
21 | case 'FETCH_PRODUCT_SUCCESS':
22 |
23 | return {
24 | ...state,
25 | fetching: false,
26 | fetched: true,
27 | data: action.data,
28 | success: true,
29 | selected: action.selected,
30 | type: 'fetch'
31 | }
32 |
33 | case 'FETCH_PRODUCT_FAILED':
34 | return {
35 | ...state,
36 | fetching: false,
37 | fetched: true,
38 | error: action.error,
39 | message: action.error.data.message,
40 | success: false,
41 | type: 'fetch'
42 | }
43 | case 'SAVE_PRODUCT_PENDING':
44 | return {
45 | ...state,
46 | fetching: true,
47 | }
48 | case 'SAVE_PRODUCT_SUCCESS':
49 |
50 | return {
51 | ...state,
52 | fetching: false,
53 | fetched: true,
54 | message: action.message,
55 | type: 'save',
56 | success: true
57 | }
58 |
59 | case 'SAVE_PRODUCT_FAILED':
60 | return {
61 | ...state,
62 | fetching: false,
63 | fetched: true,
64 | error: action.error,
65 | message: action.message,
66 | type: 'save',
67 | success: false
68 | }
69 | case 'GET_PRODUCT_PENDING':
70 | return {
71 | ...state,
72 | fetching: true,
73 | }
74 | case 'GET_PRODUCT_SUCCESS':
75 |
76 | return {
77 | ...state,
78 | fetching: false,
79 | fetched: true,
80 | type: 'get',
81 | product: action.data,
82 | success: true
83 | }
84 |
85 | case 'GET_PRODUCT_FAILED':
86 | return {
87 | ...state,
88 | fetching: false,
89 | fetched: true,
90 | error: action.error,
91 | message: action.message,
92 | type: 'get',
93 | success: false
94 | }
95 | case 'UPDATE_PRODUCT_PENDING':
96 | return {
97 | ...state,
98 | fetching: true,
99 | }
100 | case 'UPDATE_PRODUCT_SUCCESS':
101 |
102 | return {
103 | ...state,
104 | fetching: false,
105 | fetched: true,
106 | message: action.message,
107 | type: 'update',
108 | success: true
109 | }
110 |
111 | case 'UPDATE_PRODUCT_FAILED':
112 | return {
113 | ...state,
114 | fetching: false,
115 | fetched: true,
116 | error: action.error,
117 | message: action.message,
118 | type: 'update',
119 | success: false
120 | }
121 | case 'TOGGLE_PRODUCT_PENDING':
122 | return {
123 | ...state,
124 | // fetching: true,
125 | }
126 | case 'TOGGLE_PRODUCT_SUCCESS':
127 |
128 | return {
129 | ...state,
130 | // fetching: false,
131 | // fetched: true,
132 | // message: action.message,
133 | // type: 'toggle',
134 | // success: true
135 | }
136 |
137 | case 'TOGGLE_PRODUCT_FAILED':
138 | return {
139 | ...state,
140 | // fetching: false,
141 | // fetched: true,
142 | error: action.error,
143 | // message: action.message,
144 | type: 'toggle',
145 | // success: false
146 | }
147 | case 'SELECT_PRODUCT_PENDING':
148 | return {
149 | ...state,
150 | // fetching: true,
151 | }
152 | case 'SELECT_PRODUCT_SUCCESS':
153 |
154 | return {
155 | ...state,
156 | selected: action.selected
157 | // fetching: false,
158 | // fetched: true,
159 | // message: action.message,
160 | // type: 'toggle',
161 | // success: true
162 | }
163 |
164 | case 'SELECT_PRODUCT_FAILED':
165 | return {
166 | ...state,
167 | // fetching: false,
168 | // fetched: true,
169 | error: action.error,
170 | // message: action.message,
171 | type: 'toggle',
172 | // success: false
173 | }
174 | case 'DELETE_PRODUCT_PENDING':
175 | return {
176 | ...state,
177 | fetching: true,
178 | }
179 | case 'DELETE_PRODUCT_SUCCESS':
180 |
181 | return {
182 | ...state,
183 | fetching: false,
184 | fetched: true,
185 | type: 'delete',
186 | message: action.message,
187 | success: true
188 | }
189 |
190 | case 'DELETE_PRODUCT_FAILED':
191 | return {
192 | ...state,
193 | fetching: false,
194 | fetched: true,
195 | error: action.error,
196 | message: action.message,
197 | type: 'delete',
198 | success: false
199 | }
200 | case 'IMPORT_PRODUCT_PENDING':
201 | return {
202 | ...state,
203 | uploading: true,
204 | }
205 | case 'IMPORT_PRODUCT_SUCCESS':
206 |
207 | return {
208 | ...state,
209 | uploading: false,
210 | type: 'import',
211 | message: action.message,
212 | success: true
213 | }
214 |
215 | case 'IMPORT_PRODUCT_FAILED':
216 | return {
217 | ...state,
218 | uploading: false,
219 | error: action.error,
220 | message: action.message,
221 | type: 'import',
222 | success: false
223 | }
224 | default:
225 | return state
226 | }
227 | }
228 |
229 | export default productReducer
--------------------------------------------------------------------------------
/src/store/actions/PurchaseActions.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios'
2 | import { url } from '../../global'
3 | import moment from 'moment'
4 |
5 | const fetchPurchase = (params) => {
6 | return (dispatch, getState) => {
7 |
8 | const {
9 | page,
10 | perpage,
11 | keyword,
12 | ordering,
13 | filter,
14 | payment_date_start,
15 | payment_date_end,
16 | } = params
17 |
18 | dispatch({
19 | type: 'FETCH_PURCHASE_PENDING'
20 | })
21 |
22 | Axios.get(`${url}/purchase`, {
23 | params: {
24 | page,
25 | perpage,
26 | keyword,
27 | ordering,
28 | filter,
29 | payment_date_start: moment(payment_date_start).format('YYYY-MM-DD'),
30 | payment_date_end: moment(payment_date_end).format('YYYY-MM-DD'),
31 | },
32 | headers: {
33 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
34 | }
35 | }).then(res => {
36 |
37 | dispatch({
38 | type: 'FETCH_PURCHASE_SUCCESS',
39 | data: res.data.data,
40 | selected: res.data.selected
41 | })
42 |
43 | }).catch(error => {
44 |
45 | if (!error.response) {
46 | dispatch({
47 | type: 'FETCH_PURCHASE_FAILED',
48 | error: {
49 | status: null,
50 | connection: true,
51 | statusText: 'Koneksi Terputus',
52 | data: {
53 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
54 | }
55 | }
56 | })
57 |
58 | } else {
59 |
60 | dispatch({
61 | type: 'FETCH_PURCHASE_FAILED',
62 | error: error.response
63 | })
64 | }
65 |
66 | })
67 | }
68 | }
69 |
70 | const savePurchase = (data) => {
71 | return (dispatch, getState) => {
72 |
73 | const {
74 | number,
75 | payment_date,
76 | supplier_id,
77 | supplier_name,
78 | in_charge_id,
79 | in_charge_name,
80 | notes,
81 | tax,
82 | total_discount,
83 | total,
84 | subtotal,
85 | evidence,
86 | carts
87 | } = data
88 |
89 | dispatch({
90 | type: 'SAVE_PURCHASE_PENDING'
91 | })
92 |
93 |
94 | const fd = new FormData();
95 |
96 | fd.append('evidence', evidence)
97 | fd.set('payment_date', moment(payment_date).format('YYYY-MM-DD'))
98 | fd.set('number', number)
99 | fd.set('supplier_id', supplier_id)
100 | fd.set('supplier_name', supplier_name)
101 | fd.set('in_charge_id', in_charge_id)
102 | fd.set('in_charge_name', in_charge_name)
103 | fd.set('notes', notes)
104 | fd.set('tax', tax)
105 | fd.set('total_discount', total_discount)
106 | fd.set('total', total)
107 | fd.set('subtotal', subtotal)
108 | fd.set('details', JSON.stringify(carts))
109 |
110 | Axios.post(`${url}/purchase`, fd,
111 | {
112 | headers: {
113 | Authorization: `Bearer ${sessionStorage.getItem('token')}`,
114 | 'Content-Type': 'multipart/form-data'
115 | }
116 | }).then(res => {
117 |
118 | dispatch({
119 | type: 'SAVE_PURCHASE_SUCCESS',
120 | data: res.data.data,
121 | message: res.data.message
122 | })
123 |
124 | }).catch(error => {
125 |
126 | if (!error.response) {
127 | dispatch({
128 | type: 'SAVE_PURCHASE_FAILED',
129 | error: {
130 | status: null,
131 | connection: true,
132 | statusText: 'Koneksi Terputus',
133 | data: {
134 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
135 | }
136 | }
137 | })
138 |
139 | } else {
140 |
141 | dispatch({
142 | type: 'SAVE_PURCHASE_FAILED',
143 | error: error.response,
144 | message: error.response.data.message
145 | })
146 | }
147 |
148 | })
149 | }
150 | }
151 |
152 | const getPurchase = (id) => {
153 | return (dispatch, getState) => {
154 | dispatch({
155 | type: 'GET_PURCHASE_PENDING',
156 | })
157 |
158 | Axios.get(`${url}/purchase/${id}`, {
159 | headers: {
160 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
161 | }
162 | }).then(res => {
163 | dispatch({
164 | type: 'GET_PURCHASE_SUCCESS',
165 | data: res.data.data,
166 | success: true
167 | })
168 | }).catch(error => {
169 | if (!error.response) {
170 | dispatch({
171 | type: 'GET_PURCHASE_FAILED',
172 | error: {
173 | status: null,
174 | connection: true,
175 | statusText: 'Koneksi Terputus',
176 | data: {
177 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
178 | }
179 | }
180 | })
181 |
182 | } else {
183 |
184 | dispatch({
185 | type: 'GET_PURCHASE_FAILED',
186 | error: error.response,
187 | message: error.response.data.message
188 | })
189 | }
190 | })
191 | }
192 | }
193 |
194 | const deletePurchase = (id) => {
195 | return (dispatch, getState) => {
196 | dispatch({
197 | type: 'DELETE_PURCHASE_PENDING',
198 | })
199 |
200 | Axios.delete(`${url}/purchase/${id}`, {
201 | headers: {
202 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
203 | }
204 | }).then(res => {
205 | dispatch({
206 | type: 'DELETE_PURCHASE_SUCCESS',
207 | message: res.data.message,
208 | success: true
209 | })
210 | }).catch(error => {
211 | if (!error.response) {
212 | dispatch({
213 | type: 'DELETE_PURCHASE_FAILED',
214 | error: {
215 | status: null,
216 | connection: true,
217 | statusText: 'Koneksi Terputus',
218 | data: {
219 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
220 | }
221 | }
222 | })
223 |
224 | } else {
225 |
226 | dispatch({
227 | type: 'DELETE_PURCHASE_FAILED',
228 | error: error.response,
229 | message: error.response.data.message
230 | })
231 | }
232 | })
233 | }
234 | }
235 |
236 |
237 | export { fetchPurchase, savePurchase, getPurchase, deletePurchase }
--------------------------------------------------------------------------------
/src/views/Purchase/ViewPurchase.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import 'react-datepicker/dist/react-datepicker.css'
3 | import { getPurchase } from '../../store/actions/PurchaseActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import { Link } from 'react-router-dom'
7 | class ViewPurchase extends Component {
8 |
9 | componentDidMount() {
10 | this.props.getPurchase(this.props.match.params.id)
11 | }
12 |
13 | render() {
14 | const { purchase } = this.props
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
{ purchase && purchase.number }
23 |
24 |
25 | Kembali
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | | Pemasok |
38 | { purchase && purchase.supplier ? purchase.supplier.name : '-' } |
39 | Penanggung Jawab |
40 | { purchase && purchase.in_charge ? purchase.in_charge.name : '-' } |
41 |
42 |
43 | | Tanggal Pembelian |
44 | { purchase && purchase.payment_date_formatted } |
45 | Di buat oleh |
46 | { purchase && purchase.user ? purchase.user.name : '-'} |
47 |
48 |
49 | | Bukti |
50 | { purchase && purchase.evidence ? {purchase.evidence} : '-' } |
51 | Catatan |
52 | { purchase && purchase.notes } |
53 |
54 |
55 |
56 |
57 |
58 |
Pembelian
59 |
60 |
61 |
62 | | Nama Barang |
63 | Harga Beli |
64 | Harga Jual |
65 | Harga Grosir |
66 | Kuantitas |
67 | Subtotal |
68 |
69 |
70 |
71 | {
72 | purchase && purchase.details ? purchase.details.map(detail => {
73 |
74 | return (
75 |
76 | | {detail.product_name} |
77 | {detail.cost_formatted} |
78 | {detail.price_formatted} |
79 | {detail.wholesale_formatted} |
80 | {detail.qty} |
81 | {detail.subtotal_formatted} |
82 |
83 | )
84 |
85 | }) : (
86 |
87 | | Tidak ada data |
88 |
89 | )
90 | }
91 |
92 | {
93 | purchase && purchase.details && (
94 |
95 |
96 | | Subtotal |
97 | {purchase && purchase.subtotal_formatted} |
98 |
99 |
100 | | Pajak |
101 | {purchase && purchase.tax_formatted} |
102 |
103 |
104 | | Total Diskon |
105 | -{purchase && purchase.total_discount_formatted} |
106 |
107 |
108 | | Total |
109 | {purchase && purchase.total_formatted} |
110 |
111 |
112 | )
113 | }
114 |
115 |
116 |
117 |
118 |
119 |
120 | )
121 | }
122 | }
123 |
124 | const mapStateToProps = (state) => {
125 | return {
126 | ...state,
127 | purchase: state.purchase.purchase
128 | }
129 | }
130 |
131 | const mapDispatchToProps = (dispatch) => {
132 | return {
133 | getPurchase: id => dispatch(getPurchase(id))
134 | }
135 | }
136 |
137 |
138 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(ViewPurchase))
139 |
--------------------------------------------------------------------------------
/src/store/actions/ReportActions.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios'
2 | import { url } from '../../global'
3 | import moment from 'moment'
4 |
5 | const fetchSalesReport = (params) => {
6 | return (dispatch, getState) => {
7 |
8 | const {
9 | page,
10 | perpage,
11 | keyword,
12 | ordering,
13 | start_date,
14 | end_date
15 | } = params
16 |
17 | dispatch({
18 | type: 'FETCH_SALES_REPORT_PENDING'
19 | })
20 |
21 | Axios.get(`${url}/report-sales`, {
22 | params: {
23 | page,
24 | perpage,
25 | keyword,
26 | ordering,
27 | start_date: moment(start_date).format('YYYY-MM-DD'),
28 | end_date: moment(end_date).format('YYYY-MM-DD')
29 | },
30 | headers: {
31 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
32 | }
33 | }).then(res => {
34 |
35 | dispatch({
36 | type: 'FETCH_SALES_REPORT_SUCCESS',
37 | data: res.data.data,
38 | selected: res.data.selected
39 | })
40 |
41 | }).catch(error => {
42 |
43 | if (!error.response) {
44 | dispatch({
45 | type: 'FETCH_SALES_REPORT_FAILED',
46 | error: {
47 | status: null,
48 | connection: true,
49 | statusText: 'Koneksi Terputus',
50 | data: {
51 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
52 | }
53 | }
54 | })
55 |
56 | } else {
57 |
58 | dispatch({
59 | type: 'FETCH_SALES_REPORT_FAILED',
60 | error: error.response
61 | })
62 | }
63 |
64 | })
65 | }
66 | }
67 |
68 | const fetchPurchaseReport = (params) => {
69 | return (dispatch, getState) => {
70 |
71 | const {
72 | page,
73 | perpage,
74 | keyword,
75 | ordering,
76 | start_date,
77 | end_date
78 | } = params
79 |
80 | dispatch({
81 | type: 'FETCH_PURCHASE_REPORT_PENDING'
82 | })
83 |
84 | Axios.get(`${url}/report-purchase`, {
85 | params: {
86 | page,
87 | perpage,
88 | keyword,
89 | ordering,
90 | start_date: moment(start_date).format('YYYY-MM-DD'),
91 | end_date: moment(end_date).format('YYYY-MM-DD')
92 | },
93 | headers: {
94 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
95 | }
96 | }).then(res => {
97 |
98 | dispatch({
99 | type: 'FETCH_PURCHASE_REPORT_SUCCESS',
100 | data: res.data.data,
101 | selected: res.data.selected
102 | })
103 |
104 | }).catch(error => {
105 |
106 | if (!error.response) {
107 | dispatch({
108 | type: 'FETCH_PURCHASE_REPORT_FAILED',
109 | error: {
110 | status: null,
111 | connection: true,
112 | statusText: 'Koneksi Terputus',
113 | data: {
114 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
115 | }
116 | }
117 | })
118 |
119 | } else {
120 |
121 | dispatch({
122 | type: 'FETCH_PURCHASE_REPORT_FAILED',
123 | error: error.response
124 | })
125 | }
126 |
127 | })
128 | }
129 | }
130 |
131 | const fetchExpenseReport = (params) => {
132 | return (dispatch, getState) => {
133 |
134 | const {
135 | page,
136 | perpage,
137 | keyword,
138 | ordering,
139 | start_date,
140 | end_date
141 | } = params
142 |
143 | dispatch({
144 | type: 'FETCH_EXPENSE_REPORT_PENDING'
145 | })
146 |
147 | Axios.get(`${url}/report-expense`, {
148 | params: {
149 | page,
150 | perpage,
151 | keyword,
152 | ordering,
153 | start_date: moment(start_date).format('YYYY-MM-DD'),
154 | end_date: moment(end_date).format('YYYY-MM-DD')
155 | },
156 | headers: {
157 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
158 | }
159 | }).then(res => {
160 |
161 | dispatch({
162 | type: 'FETCH_EXPENSE_REPORT_SUCCESS',
163 | data: res.data.data,
164 | selected: res.data.selected
165 | })
166 |
167 | }).catch(error => {
168 |
169 | if (!error.response) {
170 | dispatch({
171 | type: 'FETCH_EXPENSE_REPORT_FAILED',
172 | error: {
173 | status: null,
174 | connection: true,
175 | statusText: 'Koneksi Terputus',
176 | data: {
177 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
178 | }
179 | }
180 | })
181 |
182 | } else {
183 |
184 | dispatch({
185 | type: 'FETCH_EXPENSE_REPORT_FAILED',
186 | error: error.response
187 | })
188 | }
189 |
190 | })
191 | }
192 | }
193 |
194 |
195 | const fetchStockReport = (params) => {
196 | return (dispatch, getState) => {
197 |
198 | const {
199 | page,
200 | perpage,
201 | keyword,
202 | ordering,
203 | start_date,
204 | end_date
205 | } = params
206 |
207 | dispatch({
208 | type: 'FETCH_STOCK_REPORT_PENDING'
209 | })
210 |
211 | Axios.get(`${url}/report-stock`, {
212 | params: {
213 | page,
214 | perpage,
215 | keyword,
216 | ordering,
217 | start_date: moment(start_date).format('YYYY-MM-DD'),
218 | end_date: moment(end_date).format('YYYY-MM-DD')
219 | },
220 | headers: {
221 | Authorization: `Bearer ${sessionStorage.getItem('token')}`
222 | }
223 | }).then(res => {
224 |
225 | dispatch({
226 | type: 'FETCH_STOCK_REPORT_SUCCESS',
227 | data: res.data.data,
228 | selected: res.data.selected
229 | })
230 |
231 | }).catch(error => {
232 |
233 | if (!error.response) {
234 | dispatch({
235 | type: 'FETCH_STOCK_REPORT_FAILED',
236 | error: {
237 | status: null,
238 | connection: true,
239 | statusText: 'Koneksi Terputus',
240 | data: {
241 | message: 'Silahkan periksa koneksi backend, lihat tutorial di sini https://github.com/kasirkita/Kasir-Kita'
242 | }
243 | }
244 | })
245 |
246 | } else {
247 |
248 | dispatch({
249 | type: 'FETCH_STOCK_REPORT_FAILED',
250 | error: error.response
251 | })
252 | }
253 |
254 | })
255 | }
256 | }
257 |
258 | export { fetchSalesReport, fetchPurchaseReport, fetchExpenseReport, fetchStockReport }
--------------------------------------------------------------------------------
/src/views/Role/EditRole.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { updateRole, getRole } from '../../store/actions/RoleActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import Error from '../Errors/Error'
7 | import { getListPermission } from '../../store/actions/PermissionAction'
8 |
9 | class EditRole extends Component {
10 |
11 | state = {
12 | name: '',
13 | permissions: {}
14 | }
15 |
16 | handleChange = (name) => (e) => {
17 | this.setState({
18 | ...this.state,
19 | [name]: e.target.value
20 | })
21 | }
22 |
23 | handleSubmit = (e) => {
24 | e.preventDefault()
25 | this.props.updateRole(this.props.match.params.id, this.state)
26 | }
27 |
28 | handleClickCheckbox = (e) => {
29 | const { permissions } = this.state
30 | this.setState({
31 | ...this.state,
32 | permissions: {
33 | ...permissions,
34 | [e.target.value]: e.target.checked
35 | }
36 | })
37 | }
38 |
39 | componentDidUpdate = (prevProps) => {
40 |
41 | const { toastManager } = this.props;
42 |
43 | if (prevProps.type !== this.props.type || prevProps.success !== this.props.success) {
44 | if (this.props.type === 'update') {
45 |
46 | if (this.props.success) {
47 |
48 | toastManager.add(this.props.message, {
49 | appearance: 'success',
50 | autoDismiss: true
51 | });
52 |
53 | return this.props.history.push('/role')
54 |
55 | } else {
56 |
57 | toastManager.add(this.props.message, {
58 | appearance: 'error',
59 | autoDismiss: true
60 | });
61 | }
62 | }
63 |
64 | if (this.props.type === 'get') {
65 |
66 | if (this.props.success) {
67 |
68 |
69 | if (this.props.role !== prevProps.role) {
70 |
71 | const { role } = this.props
72 |
73 | this.setState({
74 | ...this.state,
75 | name: role.name,
76 | permissions: role.perms
77 | })
78 | }
79 |
80 | } else {
81 |
82 | toastManager.add(this.props.message, {
83 | appearance: 'error',
84 | autoDismiss: true
85 | });
86 | }
87 |
88 | }
89 | }
90 | }
91 |
92 | componentDidMount = () => {
93 | this.props.getRole(this.props.match.params.id)
94 | this.props.getListPermssion()
95 | }
96 |
97 | render() {
98 |
99 | const { error, permissions } = this.props
100 | const { name, permissions: rolePermission } = this.state
101 | const validate = error && error.data && error.data.errors
102 |
103 |
104 | if (error && error.status !== 422)
105 | return
106 |
107 | return (
108 |
109 |
164 |
165 | )
166 | }
167 | }
168 |
169 | const mapStateToProps = state => {
170 | return {
171 | ...state,
172 | message: state.role.message,
173 | fetching: state.role.fetching,
174 | error: state.role.error,
175 | success: state.role.success,
176 | type: state.role.type,
177 | role: state.role.role,
178 | permissions: state.permission.permissions
179 | }
180 | }
181 |
182 | const mapDispatchToProps = dispatch => {
183 | return {
184 | updateRole: (id, data) => dispatch(updateRole(id, data)),
185 | getRole: id => dispatch(getRole(id)),
186 | getListPermssion: () => dispatch(getListPermission())
187 | }
188 | }
189 |
190 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(EditRole))
191 |
--------------------------------------------------------------------------------
/src/views/Supplier/EditSupplier.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { updateSupplier, getSupplier } from '../../store/actions/SupplierActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import Error from '../Errors/Error'
7 |
8 | class EditSupplier extends Component {
9 |
10 | state = {
11 | name: '',
12 | email: '',
13 | phone_number: '',
14 | address: ''
15 | }
16 |
17 | handleSave = () => {
18 | this.props.updateSupplier(this.props.match.params.id, this.state)
19 | }
20 |
21 | handleReset = () => {
22 |
23 | this.setState({
24 | name: '',
25 | email: '',
26 | phone_number: '',
27 | address: ''
28 | })
29 | }
30 |
31 | handleChange = (name) => (e) => {
32 | this.setState({
33 | ...this.state,
34 | [name]: e.target.value
35 | })
36 | }
37 |
38 | componentDidUpdate = (prevProps) => {
39 |
40 | const { toastManager } = this.props;
41 |
42 | if (prevProps.type !== this.props.type || prevProps.success !== this.props.success) {
43 | if (this.props.type === 'update') {
44 |
45 | if (this.props.success) {
46 |
47 | toastManager.add(this.props.message, {
48 | appearance: 'success',
49 | autoDismiss: true
50 | });
51 |
52 | return this.props.history.push('/supplier')
53 |
54 | } else {
55 |
56 | toastManager.add(this.props.message, {
57 | appearance: 'error',
58 | autoDismiss: true
59 | });
60 | }
61 | }
62 |
63 | if (this.props.type === 'get') {
64 |
65 | if (this.props.success) {
66 |
67 |
68 | if (this.props.supplier !== prevProps.supplier) {
69 |
70 | const { supplier } = this.props
71 |
72 | this.setState({
73 | ...this.state,
74 | name: supplier.name,
75 | email: supplier.email,
76 | phone_number: supplier.phone_number,
77 | address: supplier.address,
78 | })
79 | }
80 |
81 | } else {
82 |
83 | toastManager.add(this.props.message, {
84 | appearance: 'error',
85 | autoDismiss: true
86 | });
87 | }
88 |
89 | }
90 | }
91 | }
92 |
93 | componentDidMount(){
94 | this.props.getSupplier(this.props.match.params.id)
95 | }
96 |
97 |
98 | render() {
99 |
100 | const { error, fetching } = this.props
101 |
102 | const {
103 | name,
104 | email,
105 | phone_number,
106 | address
107 | } = this.state
108 |
109 | const validate = error && error.data && error.data.errors
110 |
111 | if (error && error.status !== 422)
112 | return
113 |
114 | return (
115 |
116 |
117 |
118 |
119 |
120 |
121 |
Ubah Pemasok
122 |
123 |
124 | Kembali
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | {
136 | validate && validate.name && (
137 |
{ validate.name[0] }
138 | )
139 | }
140 |
141 |
142 |
143 |
144 |
145 |
146 | {
147 | validate && validate.email && (
148 |
{ validate.email[0] }
149 | )
150 | }
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | {
172 | fetching ? (
173 |
174 | ) : (
175 |
176 | )
177 | }
178 |
179 |
180 |
181 | )
182 | }
183 | }
184 |
185 | const mapStateToProps = state => {
186 | return {
187 | ...state,
188 | message: state.supplier.message,
189 | fetching: state.supplier.fetching,
190 | error: state.supplier.error,
191 | success: state.supplier.success,
192 | type: state.supplier.type,
193 | supplier: state.supplier.supplier
194 | }
195 | }
196 |
197 | const mapDispatchToProps = dispatch => {
198 | return {
199 | updateSupplier: (id, data) => dispatch(updateSupplier(id, data)),
200 | getSupplier: id => dispatch(getSupplier(id))
201 | }
202 | }
203 |
204 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(EditSupplier))
--------------------------------------------------------------------------------
/src/views/Sales/ViewSales.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react'
2 | import 'react-datepicker/dist/react-datepicker.css'
3 | import { getSales } from '../../store/actions/SalesActions'
4 | import { connect } from 'react-redux'
5 | import { withToastManager } from 'react-toast-notifications'
6 | import { Link } from 'react-router-dom'
7 | class ViewSales extends Component {
8 |
9 | componentDidMount() {
10 | this.props.getSales(this.props.match.params.id)
11 | }
12 |
13 | render() {
14 | const { sales } = this.props
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
{ sales && sales.number }
23 |
24 |
25 | Kembali
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | | Pelanggan |
38 | { sales && sales.customer ? sales.customer.name : '-' } |
39 | Kasir |
40 | { sales && sales.user ? sales.user.name : '-' } |
41 |
42 |
43 | | Metode Pembayaran |
44 | { sales && sales.payment_type === 'cash' ? 'Tunai' : 'Kartu' } |
45 | Status |
46 | { sales && sales.status === 'done' ? Selesai : Ditahan } |
47 |
48 |
49 |
50 |
51 |
52 |
Belanjaan
53 |
54 |
55 |
56 | | Nama Barang |
57 | Harga |
58 | Kuantitas |
59 | Diskon |
60 | Subtotal |
61 |
62 |
63 |
64 | {
65 | sales && sales.details ? sales.details.map(detail => {
66 |
67 | return (
68 |
69 | | {detail.product_name} |
70 | {detail.price_formatted} |
71 | {detail.qty} |
72 | -{detail.discount_formatted} |
73 | {detail.subtotal_formatted} |
74 |
75 | )
76 |
77 | }) : (
78 |
79 | | Tidak ada data |
80 |
81 | )
82 | }
83 |
84 | {
85 | sales && sales.details && (
86 |
87 |
88 | | Subtotal |
89 | {sales && sales.subtotal_formatted} |
90 |
91 |
92 | | Pajak |
93 | {sales && sales.tax_formatted} |
94 |
95 |
96 | | Total Diskon |
97 | -{sales && sales.total_discount_formatted} |
98 |
99 |
100 | | Total |
101 | {sales && sales.total_formatted} |
102 |
103 | {
104 | sales && sales.payment_type === 'cash' && (
105 |
106 |
107 |
108 | | Pembayaran |
109 | {sales && sales.amount_formatted} |
110 |
111 |
112 | | Kembalian |
113 | {sales && sales.change_formatted} |
114 |
115 |
116 | )
117 | }
118 |
119 | )
120 | }
121 |
122 |
123 |
124 |
125 |
126 |
127 | )
128 | }
129 | }
130 |
131 | const mapStateToProps = (state) => {
132 | return {
133 | ...state,
134 | sales: state.sales.sales
135 | }
136 | }
137 |
138 | const mapDispatchToProps = (dispatch) => {
139 | return {
140 | getSales: id => dispatch(getSales(id))
141 | }
142 | }
143 |
144 |
145 | export default connect(mapStateToProps, mapDispatchToProps)(withToastManager(ViewSales))
146 |
--------------------------------------------------------------------------------