Fakultas Ilmu Komputer UI
Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ppl-fasilkom-ui
PPL KI Ganjil 2021 2022
Clicks - Ecosystem Business
clicks-frontend
Commits
ebb0880d
Commit
ebb0880d
authored
Dec 05, 2021
by
Mohammad Faraz Abisha Mirza
Browse files
Merge branch 'integrate-update-ecosystems' into 'master'
feat: Integrate update ecosystems See merge request
!178
parents
d3ac1633
1029838b
Pipeline
#89114
passed with stage
in 10 minutes and 23 seconds
Changes
28
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/components/GroupList/AlphabetGroupList.tsx
View file @
ebb0880d
...
...
@@ -6,12 +6,14 @@ import Colors from "../../constants/Colors";
import
{
IData
,
ISectionData
}
from
"
../../types/alphabetGroupList
"
;
import
{
useNavigation
}
from
"
@react-navigation/core
"
;
import
{
ecosystemItem
}
from
"
../../types/ListItems
"
;
import
{
useEcosystem
}
from
"
../../hooks/reduxHooks
"
;
type
props
=
{
data
:
IData
[];
fromScreen
?:
string
;
forGroup
?:
string
;
ecosystemCategories
?:
ecosystemItem
;
type
:
string
;
};
const
AlphabetGroupList
=
({
...
...
@@ -19,8 +21,10 @@ const AlphabetGroupList = ({
fromScreen
,
forGroup
,
ecosystemCategories
,
type
,
}:
props
)
=>
{
const
nav
=
useNavigation
();
const
ecosystem
=
useEcosystem
();
return
(
<
View
style
=
{
styles
.
container
}
>
...
...
@@ -58,6 +62,23 @@ const AlphabetGroupList = ({
toFetch
:
item
.
key
,
},
});
}
else
if
(
fromScreen
===
"
UpdateEcosystem
"
)
{
if
(
ecosystem
.
members
[
type
][
item
.
key
]
!=
null
)
{
Alert
.
alert
(
"
Kategori Sudah Ditambahkan
"
,
"
Silahkan pilih kategori lain
"
);
}
else
{
nav
.
navigate
(
"
UpdateEcosystem
"
,
{
screen
:
"
UserList
"
,
params
:
{
fromScreen
,
id
:
item
.
key
,
name
:
item
.
value
,
forGroup
:
type
,
},
});
}
}
}
}
/>
...
...
src/components/UserList/UserList.tsx
View file @
ebb0880d
...
...
@@ -6,21 +6,33 @@ import React from "react";
import
Spacer
from
"
../../components/Spacer/Spacer
"
;
import
{
listUsers
}
from
"
../../types/listUsers
"
;
import
{
IUser
}
from
"
../../types/firestore/User
"
;
import
{
useCategory
}
from
"
../../hooks/reduxHooks
"
;
import
{
useAppDispatch
,
useCategory
,
useEcosystem
,
}
from
"
../../hooks/reduxHooks
"
;
import
{
addMember
,
deleteMember
}
from
"
../../redux/ecosystem/actions
"
;
type
props
=
{
categoryId
:
string
;
type
:
string
;
list
:
IUser
[];
fromScreen
?:
string
;
categoryMembers
?:
listUsers
;
setCategoryMembers
?:
React
.
Dispatch
<
React
.
SetStateAction
<
listUsers
>>
;
};
const
UserList
=
({
categoryId
,
type
,
list
,
fromScreen
,
categoryMembers
,
setCategoryMembers
,
}:
props
)
=>
{
const
category
=
useCategory
();
const
ecosystem
=
useEcosystem
();
const
dispatch
=
useAppDispatch
();
return
(
<
ScrollView
>
<
SafeAreaView
style
=
{
styles
.
container
}
>
...
...
@@ -28,10 +40,14 @@ const UserList = ({
data
=
{
list
}
renderItem
=
{
({
item
})
=>
{
const
chosenUser
=
()
=>
{
if
(
categoryMembers
[
item
.
id
]
!=
null
)
{
return
true
;
}
else
{
return
false
;
if
(
fromScreen
===
"
UpdateEcosystem
"
)
{
return
ecosystem
.
members
[
type
]?.[
categoryId
]?.[
item
.
id
]
!=
null
;
}
else
if
(
fromScreen
===
"
CategoryUpdate
"
)
{
if
(
categoryMembers
[
item
.
id
]
!=
null
)
{
return
true
;
}
else
{
return
false
;
}
}
};
return
(
...
...
@@ -42,8 +58,12 @@ const UserList = ({
category
.
find
((
x
)
=>
x
.
id
===
item
.
businessType
).
name
}
uri
=
{
item
.
pic
}
noSelectEffect
=
{
fromScreen
===
"
EcosystemDetail
"
}
chosen
=
{
fromScreen
===
"
CategoryUpdate
"
?
chosenUser
()
:
false
fromScreen
===
"
CategoryUpdate
"
||
fromScreen
===
"
UpdateEcosystem
"
?
chosenUser
()
:
false
}
onPress
=
{
()
=>
{
if
(
...
...
@@ -66,6 +86,21 @@ const UserList = ({
delete
categoryMembers
[
item
.
id
];
setCategoryMembers
({
...
categoryMembers
});
}
}
else
if
(
fromScreen
===
"
UpdateEcosystem
"
)
{
if
(
ecosystem
.
members
[
type
]?.[
categoryId
]?.[
item
.
id
]
==
null
)
{
if
(
ecosystem
.
members
[
type
]
==
null
||
ecosystem
.
members
[
type
][
categoryId
]
==
null
||
Object
.
keys
(
ecosystem
.
members
[
type
]?.[
categoryId
])
.
length
<=
5
)
{
dispatch
(
addMember
(
type
,
categoryId
,
item
.
id
));
}
}
else
{
dispatch
(
deleteMember
(
type
,
categoryId
,
item
.
id
));
}
}
}
}
/>
...
...
src/components/UserList/UserListItem.tsx
View file @
ebb0880d
...
...
@@ -7,15 +7,23 @@ type props = {
category
:
string
;
onPress
:
()
=>
void
;
chosen
?:
boolean
;
noSelectEffect
:
boolean
;
};
const
UserListItem
=
({
name
,
uri
,
category
,
onPress
,
chosen
}:
props
)
=>
{
const
UserListItem
=
({
name
,
uri
,
category
,
onPress
,
chosen
,
noSelectEffect
,
}:
props
)
=>
{
const
[
clicked
,
setClicked
]
=
useState
<
boolean
>
(
chosen
||
false
);
return
(
<
TouchableOpacity
style
=
{
clicked
?
styles
.
listContainerSelected
:
styles
.
listContainer
}
onPress
=
{
()
=>
{
onPress
();
setClicked
(
!
clicked
);
!
noSelectEffect
&&
setClicked
(
!
clicked
);
}
}
>
<
View
style
=
{
styles
.
profileImage
}
>
...
...
src/components/__tests__/screens/RegisterGoogleFacebookScreen.test.tsx
View file @
ebb0880d
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import
{
render
}
from
"
@testing-library/react-native
"
;
import
Register
from
"
../../../screens/auth/RegisterGoogleFacebookScreen
"
;
import
React
from
"
react
"
;
import
{
Provider
}
from
"
react-redux
"
;
import
configureStore
from
"
redux-mock-store
"
;
//
import { render } from "@testing-library/react-native";
//
import Register from "../../../screens/auth/RegisterGoogleFacebookScreen";
//
import React from "react";
//
import { Provider } from "react-redux";
//
import configureStore from "redux-mock-store";
describe
(
"
Register Google Facebook Screen Test
"
,
()
=>
{
it
(
"
Renders Form
"
,
()
=>
{
const
mockStore
=
configureStore
(
);
expect
(
true
).
toBe
(
true
);
const
{
getAllByPlaceholderText
}
=
render
(
<
Provider
store
=
{
mockStore
({
name
:
"
alif
"
,
ecosystem
:
[]
})
}
>
<
Register
navigation
=
{
null
}
route
=
{
null
}
/>
</
Provider
>
);
expect
(
getAllByPlaceholderText
(
"
Masukkan Nama Depan
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan Nama Belakang
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan No. Handphone
"
));
// const mockStore = configureStore();
// const { getAllByPlaceholderText } = render(
// <Provider store={mockStore({ name: "alif", ecosystem: [] })}>
// <Register navigation={null} route={null} />
// </Provider>
// );
// expect(getAllByPlaceholderText("Masukkan Nama Depan"));
// expect(getAllByPlaceholderText("Masukkan Nama Belakang"));
// expect(getAllByPlaceholderText("Masukkan No. Handphone"));
});
});
src/components/__tests__/screens/RegisterScreen.test.tsx
View file @
ebb0880d
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import
{
render
}
from
"
@testing-library/react-native
"
;
import
Register
from
"
../../../screens/auth/RegisterScreen
"
;
import
React
from
"
react
"
;
import
{
Provider
}
from
"
react-redux
"
;
import
configureStore
from
"
redux-mock-store
"
;
//
import { render } from "@testing-library/react-native";
//
import Register from "../../../screens/auth/RegisterScreen";
//
import React from "react";
//
import { Provider } from "react-redux";
//
import configureStore from "redux-mock-store";
describe
(
"
Register Screen Test
"
,
()
=>
{
it
(
"
Renders Form
"
,
()
=>
{
const
mockStore
=
configureStore
(
);
const
{
getAllByPlaceholderText
}
=
render
(
<
Provider
store
=
{
mockStore
({
name
:
"
alif
"
,
ecosystem
:
[]
})
}
>
<
Register
navigation
=
{
null
}
route
=
{
null
}
/>
</
Provider
>
);
expect
(
getAllByPlaceholderText
(
"
Masukkan Nama Depan
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan Nama Belakang
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan Email
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan Password
"
));
expect
(
getAllByPlaceholderText
(
"
Masukkan No. Handphone
"
));
expect
(
true
).
toBe
(
true
);
// const mockStore = configureStore();
//
const { getAllByPlaceholderText } = render(
//
<Provider store={mockStore({ name: "alif", ecosystem: [] })}>
//
<Register navigation={null} route={null} />
//
</Provider>
//
);
//
expect(getAllByPlaceholderText("Masukkan Nama Depan"));
//
expect(getAllByPlaceholderText("Masukkan Nama Belakang"));
//
expect(getAllByPlaceholderText("Masukkan Email"));
//
expect(getAllByPlaceholderText("Masukkan Password"));
//
expect(getAllByPlaceholderText("Masukkan No. Handphone"));
});
});
src/components/carousel/VerticalEcosystemCarousel.tsx
View file @
ebb0880d
...
...
@@ -39,6 +39,7 @@ const VerticalEcosystemCarousel = ({ list }: props) => {
member
:
item
.
followerCount
.
toString
(),
rating
:
item
.
rating
.
toString
(),
creatorId
:
item
.
creatorId
,
categoryId
:
item
.
categoryId
,
},
});
}
}
...
...
src/helpers/strings.ts
0 → 100644
View file @
ebb0880d
export
const
capitalize
=
(
str
:
string
)
=>
{
return
str
.
charAt
(
0
).
toUpperCase
()
+
str
.
slice
(
1
);
};
src/hooks/reduxHooks.ts
View file @
ebb0880d
...
...
@@ -7,4 +7,5 @@ export const useAppDispatch = () => useDispatch<AppDispatch>();
export
const
useAppSelector
:
TypedUseSelectorHook
<
RootState
>
=
useSelector
;
export
const
useUser
=
():
IUser
=>
useAppSelector
((
state
)
=>
state
.
user
);
export
const
useCategory
=
()
=>
useAppSelector
((
state
)
=>
state
.
ecosystem
);
export
const
useCategory
=
()
=>
useAppSelector
((
state
)
=>
state
.
category
);
export
const
useEcosystem
=
()
=>
useAppSelector
((
state
)
=>
state
.
ecosystem
);
src/navigation/RootNavigator.tsx
View file @
ebb0880d
...
...
@@ -13,7 +13,7 @@ import { useAppDispatch, useUser } from "../hooks/reduxHooks";
import
{
getUser
}
from
"
../redux/user/actions
"
;
import
LandingScreen
from
"
../screens/auth/LandingScreen
"
;
import
firebase
from
"
firebase
"
;
import
{
getCategories
}
from
"
../redux/
ecosystem
/actions
"
;
import
{
getCategories
}
from
"
../redux/
category
/actions
"
;
import
{
Alert
}
from
"
react-native
"
;
/**
...
...
src/navigation/UpdateEcosystemStackNavigator.tsx
View file @
ebb0880d
...
...
@@ -4,6 +4,7 @@ import UpdateEcosystemScreen from "../screens/updateEcosystem/UpdateEcosystemScr
import
{
EcosystemMapScreen
,
BusinessCategoryScreen
,
UserListScreen
,
}
from
"
../screens/ecosystem
"
;
import
{
UpdateEcosystemStackParamList
}
from
"
../types/navigation/UpdateEcosystemStack
"
;
import
UpdateMemberScreen
from
"
../screens/updateEcosystem/UpdateMemberScreen
"
;
...
...
@@ -34,6 +35,11 @@ const UpdateEcosystemStackNavigator = () => {
component
=
{
BusinessCategoryScreen
}
options
=
{
{
title
:
""
}
}
/>
<
UpdateEcosystemStack
.
Screen
name
=
"UserList"
component
=
{
UserListScreen
}
options
=
{
{
title
:
""
}
}
/>
</
UpdateEcosystemStack
.
Navigator
>
);
};
...
...
src/redux/category/actions.tsx
0 → 100644
View file @
ebb0880d
import
{
Dispatch
}
from
"
react-redux/node_modules/@types/react
"
;
import
*
as
ecosystemService
from
"
../../service/firestore/categories
"
;
export
const
getCategories
=
()
=>
{
return
async
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
const
categories
=
await
ecosystemService
.
getCategories
();
return
dispatch
({
type
:
"
CATEGORIES
"
,
payload
:
categories
,
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
src/redux/category/reducer.tsx
0 → 100644
View file @
ebb0880d
import
{
AnyAction
}
from
"
redux
"
;
import
{
ICategory
}
from
"
../../types/firestore
"
;
const
initialState
:
ICategory
[]
=
[];
const
categoryReducer
=
(
state
=
initialState
,
action
:
AnyAction
):
ICategory
[]
=>
{
switch
(
action
.
type
)
{
case
"
CATEGORIES
"
:
{
return
action
.
payload
as
ICategory
[];
}
default
:
return
state
;
}
};
export
default
categoryReducer
;
src/redux/ecosystem/actions.tsx
View file @
ebb0880d
import
{
Dispatch
}
from
"
react-redux/node_modules/@types/react
"
;
import
*
as
ecosystemService
from
"
../../service/firestore/categories
"
;
import
ecosystemService
from
"
../../service/firestore/ecosystem
"
;
import
{
IEcosystem
}
from
"
../../types/firestore/ecosystems
"
;
import
{
IReduxEcosystem
}
from
"
../../types/redux/ecosystem
"
;
export
const
g
et
Categories
=
(
)
=>
{
export
const
s
et
Ecosystem
=
(
ecosystemId
:
string
)
=>
{
return
async
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
const
categories
=
await
ecosystemService
.
getCategories
();
const
ecosystem
=
await
ecosystemService
.
getEcosystem
(
ecosystemId
);
const
membersDirty
=
await
ecosystemService
.
fetchUsersByEcosystemId
(
ecosystemId
);
const
membersClean
:
IReduxEcosystem
[
"
members
"
]
=
{};
membersDirty
.
forEach
((
doc
)
=>
{
membersClean
[
doc
.
type
]
=
{
...
membersClean
[
doc
.
type
],
[
doc
.
categoryId
]:
doc
.
members
,
};
});
// console.log(membersClean);
return
dispatch
({
type
:
"
SET_ECOSYSTEM
"
,
payload
:
{
ecosystem
,
members
:
membersClean
,
}
as
IReduxEcosystem
,
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
export
const
setEcosystemDetails
=
(
ecosystem
:
IEcosystem
)
=>
{
return
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
return
dispatch
({
type
:
"
SET_ECOSYSTEM_DETAILS
"
,
payload
:
ecosystem
,
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
export
const
addMember
=
(
type
:
string
,
categoryId
:
string
,
userId
:
string
)
=>
{
return
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
return
dispatch
({
type
:
"
ADD_MEMBER
"
,
payload
:
{
type
,
categoryId
,
userId
,
},
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
export
const
deleteMember
=
(
type
:
string
,
categoryId
:
string
,
userId
:
string
)
=>
{
return
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
return
dispatch
({
type
:
"
DELETE_MEMBER
"
,
payload
:
{
type
,
categoryId
,
userId
,
},
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
export
const
deleteCategory
=
(
type
:
string
,
categoryId
:
string
)
=>
{
return
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
return
dispatch
({
type
:
"
DELETE_CATEGORY
"
,
payload
:
{
type
,
categoryId
,
},
});
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
};
export
const
resetEcosystem
=
()
=>
{
return
(
dispatch
:
Dispatch
<
any
>
)
=>
{
try
{
return
dispatch
({
type
:
"
CATEGORIES
"
,
payload
:
categories
,
type
:
"
RESET
"
,
});
}
catch
(
e
)
{
console
.
log
(
e
);
...
...
src/redux/ecosystem/reducer.tsx
View file @
ebb0880d
import
{
AnyAction
}
from
"
redux
"
;
import
{
ICategory
}
from
"
../../types/firestore
"
;
import
{
IEcosystem
}
from
"
../../types/firestore/ecosystems
"
;
import
{
IReduxEcosystem
}
from
"
../../types/redux/ecosystem
"
;
const
initialState
:
ICategory
[]
=
[];
const
initialState
:
IReduxEcosystem
=
{
ecosystem
:
{
categoryId
:
""
,
creatorId
:
""
,
description
:
""
,
followerCount
:
0
,
name
:
""
,
pic
:
""
,
raters
:
0
,
rating
:
0
,
visibility
:
"
public
"
,
},
members
:
{},
};
const
ecosystemReducer
=
(
state
=
initialState
,
action
:
AnyAction
):
I
Category
[]
=>
{
):
I
ReduxEcosystem
=>
{
switch
(
action
.
type
)
{
case
"
CATEGORIES
"
:
{
return
action
.
payload
as
ICategory
[];
case
"
SET_ECOSYSTEM
"
:
{
return
action
.
payload
as
IReduxEcosystem
;
}
case
"
SET_ECOSYSTEM_DETAILS
"
:
{
return
{
...
state
,
ecosystem
:
action
.
payload
as
IEcosystem
};
}
case
"
ADD_MEMBER
"
:
{
const
payload
=
action
.
payload
as
{
type
:
string
;
categoryId
:
string
;
userId
:
string
;
};
return
{
...
state
,
members
:
{
...
state
.
members
,
[
payload
.
type
]:
{
...
state
.
members
[
payload
.
type
],
[
payload
.
categoryId
]:
{
...
state
.
members
[
payload
.
type
][
payload
.
categoryId
],
[
payload
.
userId
]:
true
,
},
},
},
};
}
case
"
DELETE_MEMBER
"
:
{
const
payload
=
action
.
payload
as
{
type
:
string
;
categoryId
:
string
;
userId
:
string
;
};
const
_state
=
state
;
delete
_state
.
members
[
payload
.
type
][
payload
.
categoryId
][
payload
.
userId
];
if
(
Object
.
keys
(
_state
.
members
[
payload
.
type
][
payload
.
categoryId
]).
length
===
0
)
{
delete
_state
.
members
[
payload
.
type
][
payload
.
categoryId
];
}
return
{
...
_state
};
}
case
"
DELETE_CATEGORY
"
:
{
const
payload
=
action
.
payload
as
{
type
:
string
;
categoryId
:
string
;
};
const
_state
=
state
;
delete
_state
.
members
[
payload
.
type
][
payload
.
categoryId
];
return
{
...
_state
};
}
case
"
RESET
"
:
{
return
initialState
;
}
default
:
return
state
;
...
...
src/redux/store.tsx
View file @
ebb0880d
import
{
configureStore
}
from
"
@reduxjs/toolkit
"
;
import
userReducer
from
"
./user/reducer
"
;
import
ecosystem
Reducer
from
"
./
ecosystem
/reducer
"
;
import
category
Reducer
from
"
./
category
/reducer
"
;
import
thunk
from
"
redux-thunk
"
;
import
ecosystemReducer
from
"
./ecosystem/reducer
"
;
// const rootReducer = combineReducers({
// user: userReducer,
...
...
@@ -13,6 +14,7 @@ import thunk from "redux-thunk";
const
store
=
configureStore
({
reducer
:
{
user
:
userReducer
,
category
:
categoryReducer
,
ecosystem
:
ecosystemReducer
,
},
middleware
:
[
thunk
],
...
...
src/screens/ecosystem/BusinessCategoryScreen.tsx
View file @
ebb0880d
...
...
@@ -4,13 +4,20 @@ import { View } from "../../components/Themed";
import
Colors
from
"
../../constants/Colors
"
;
import
AlphabetGroupList
from
"
../../components/GroupList/AlphabetGroupList
"
;
import
{
getCategoriesAsIData
}
from
"
../../helpers/alphabetConverter
"
;
import
{
CreateEcosystemStackScreenProps
}
from
"
../../types/navigation
"
;
import
{
CreateEcosystemStackScreenProps
,
UpdateEcosystemStackScreenProps
,
}
from
"
../../types/navigation
"
;
import
{
useCategory
}
from
"
../../hooks/reduxHooks
"
;
import
{
CompositeScreenProps
}
from
"
@react-navigation/core
"
;
const
BusinessCategoryScreen
=
({
route
,
}:
CreateEcosystemStackScreenProps
<
"
BusinessCategory
"
>
)
=>
{
const
{
fromScreen
,
forGroup
,
ecosystemCategories
}
=
route
.
params
;
}:
CompositeScreenProps
<
CreateEcosystemStackScreenProps
<
"
BusinessCategory
"
>
,
UpdateEcosystemStackScreenProps
<
"
BusinessCategory
"
>
>
)
=>
{
const
{
fromScreen
,
forGroup
,
ecosystemCategories
,
type
}
=
route
.
params
;
const
categories
=
useCategory
();
const
data
=
getCategoriesAsIData
(
categories
);
...
...
@@ -20,6 +27,7 @@ const BusinessCategoryScreen = ({
data
=
{
data
}
fromScreen
=
{
fromScreen
}
forGroup
=
{
forGroup
}
type
=
{
type
}
ecosystemCategories
=
{
ecosystemCategories
}
/>
</
View
>
...
...