Compare commits
32 Commits
amalia/09-
...
amalia/26-
| Author | SHA1 | Date | |
|---|---|---|---|
| bd82b7c427 | |||
| a6c96105d2 | |||
| 14e9bf15c7 | |||
| 907b56feaf | |||
| 2341a46992 | |||
| 43a91c6481 | |||
| ecc41c905f | |||
| 65d53951c3 | |||
| c2597b25bf | |||
| f1b3eecbbe | |||
| f042e32d98 | |||
| 93c492ac71 | |||
| 6cca0a3d08 | |||
| bbb25a30d2 | |||
| 46e269b45f | |||
| 4725d27f74 | |||
| ae74791a1c | |||
| ba453ad027 | |||
| 187e9dd19e | |||
| 040cab4f5e | |||
| 7442d01551 | |||
| 180fbeede9 | |||
| d0d40cb1a7 | |||
| 8a25c2f672 | |||
| d31c3677c9 | |||
| 19b02ffc01 | |||
| b9b615636b | |||
| d3e7ef9623 | |||
| 89bf659598 | |||
| c435eb1503 | |||
| 75c95b5c92 | |||
| bc590b8cb5 |
@@ -39,5 +39,7 @@ app-example
|
|||||||
|
|
||||||
x.ts
|
x.ts
|
||||||
x.sh
|
x.sh
|
||||||
/android
|
|
||||||
/ios
|
.env
|
||||||
|
|
||||||
|
android/
|
||||||
4
android/.kotlin/errors/errors-1757572005452.log
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
kotlin version: 2.0.21
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||||
|
1. Kotlin compile daemon is ready
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ export default {
|
|||||||
expo: {
|
expo: {
|
||||||
name: "Desa+",
|
name: "Desa+",
|
||||||
slug: "mobile-darmasaba",
|
slug: "mobile-darmasaba",
|
||||||
version: "1.0.3",
|
version: "1.0.5", // Versi aplikasi (App Store)
|
||||||
jsEngine: "jsc",
|
jsEngine: "jsc",
|
||||||
orientation: "portrait",
|
orientation: "portrait",
|
||||||
icon: "./assets/images/logo-icon-small.png",
|
icon: "./assets/images/logo-icon-small.png",
|
||||||
@@ -14,15 +14,16 @@ export default {
|
|||||||
ios: {
|
ios: {
|
||||||
supportsTablet: true,
|
supportsTablet: true,
|
||||||
bundleIdentifier: "mobiledarmasaba.app",
|
bundleIdentifier: "mobiledarmasaba.app",
|
||||||
|
buildNumber: "2",
|
||||||
infoPlist: {
|
infoPlist: {
|
||||||
ITSAppUsesNonExemptEncryption: false,
|
ITSAppUsesNonExemptEncryption: false,
|
||||||
CFBundleDisplayName: "Desa+"
|
CFBundleDisplayName: "Desa+"
|
||||||
},
|
},
|
||||||
googleServicesFile: "./ios/Desa/GoogleService-Info.plist"
|
googleServicesFile: process.env.IOS_GOOGLE_SERVICES_FILE
|
||||||
},
|
},
|
||||||
android: {
|
android: {
|
||||||
package: "mobiledarmasaba.app",
|
package: "mobiledarmasaba.app",
|
||||||
versionCode: 7,
|
versionCode: 9,
|
||||||
adaptiveIcon: {
|
adaptiveIcon: {
|
||||||
foregroundImage: "./assets/images/logo-icon-small.png",
|
foregroundImage: "./assets/images/logo-icon-small.png",
|
||||||
backgroundColor: "#ffffff"
|
backgroundColor: "#ffffff"
|
||||||
@@ -59,7 +60,7 @@ export default {
|
|||||||
"@react-native-firebase/app",
|
"@react-native-firebase/app",
|
||||||
{
|
{
|
||||||
ios: {
|
ios: {
|
||||||
googleServicesFile: "./ios/Desa/GoogleService-Info.plist"
|
googleServicesFile: process.env.IOS_GOOGLE_SERVICES_FILE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -153,14 +153,13 @@ export default function DetailDiscussionGeneral() {
|
|||||||
<MaterialIcons name="chat" size={25} color={'#384288'} />
|
<MaterialIcons name="chat" size={25} color={'#384288'} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
title={data?.title}
|
title={data?.title + " " + data?.createdAt}
|
||||||
subtitle={
|
subtitle={
|
||||||
!data?.isActive ?
|
!data?.isActive ?
|
||||||
<LabelStatus category='warning' text='ARSIP' size="small" />
|
<LabelStatus category='warning' text='ARSIP' size="small" />
|
||||||
:
|
:
|
||||||
<LabelStatus category={data.status == 1 ? 'success' : 'error'} text={data.status == 1 ? 'BUKA' : 'TUTUP'} size="small" />
|
<LabelStatus category={data.status == 1 ? 'success' : 'error'} text={data.status == 1 ? 'BUKA' : 'TUTUP'} size="small" />
|
||||||
}
|
}
|
||||||
rightTopInfo={data?.createdAt}
|
|
||||||
desc={data?.desc}
|
desc={data?.desc}
|
||||||
leftBottomInfo={
|
leftBottomInfo={
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
@@ -168,6 +167,11 @@ export default function DetailDiscussionGeneral() {
|
|||||||
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{dataKomentar.length} Komentar</Text>
|
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{dataKomentar.length} Komentar</Text>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
rightBottomInfo={
|
||||||
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
|
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{data?.createdAt}</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<View style={[Styles.p15]}>
|
<View style={[Styles.p15]}>
|
||||||
@@ -214,11 +218,16 @@ export default function DetailDiscussionGeneral() {
|
|||||||
bg="white"
|
bg="white"
|
||||||
onChange={setKomentar}
|
onChange={setKomentar}
|
||||||
value={komentar}
|
value={komentar}
|
||||||
|
multiline
|
||||||
itemRight={
|
itemRight={
|
||||||
<Pressable onPress={() => {
|
<Pressable onPress={() => {
|
||||||
(komentar != '' && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
(komentar != '' && data?.status === 1 && data?.isActive && (memberDiscussion || (entityUser.role != "user" && entityUser.role != "coadmin")))
|
||||||
&& handleKomentar()
|
&& handleKomentar()
|
||||||
}}>
|
}}
|
||||||
|
style={[
|
||||||
|
Platform.OS == 'android' && Styles.mb15,
|
||||||
|
]}
|
||||||
|
>
|
||||||
<MaterialIcons name="send" size={25} style={(komentar == '' || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? Styles.cGray : Styles.cDefault} />
|
<MaterialIcons name="send" size={25} style={(komentar == '' || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? Styles.cGray : Styles.cDefault} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,22 +98,26 @@ export default function Discussion() {
|
|||||||
return (
|
return (
|
||||||
<View style={[Styles.p15, { flex: 1 }]}>
|
<View style={[Styles.p15, { flex: 1 }]}>
|
||||||
<View>
|
<View>
|
||||||
<View style={[Styles.wrapBtnTab]}>
|
{
|
||||||
<ButtonTab
|
entityUser.role != "user" && entityUser.role != "coadmin" &&
|
||||||
active={status == "false" ? "false" : "true"}
|
<View style={[Styles.wrapBtnTab]}>
|
||||||
value="true"
|
<ButtonTab
|
||||||
onPress={() => { setStatus("true") }}
|
active={status == "false" ? "false" : "true"}
|
||||||
label="Aktif"
|
value="true"
|
||||||
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
|
onPress={() => { setStatus("true") }}
|
||||||
n={2} />
|
label="Aktif"
|
||||||
<ButtonTab
|
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
|
||||||
active={status == "false" ? "false" : "true"}
|
n={2} />
|
||||||
value="false"
|
<ButtonTab
|
||||||
onPress={() => { setStatus("false") }}
|
active={status == "false" ? "false" : "true"}
|
||||||
label="Arsip"
|
value="false"
|
||||||
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
|
onPress={() => { setStatus("false") }}
|
||||||
n={2} />
|
label="Arsip"
|
||||||
</View>
|
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
|
||||||
|
n={2} />
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
<InputSearch onChange={setSearch} />
|
<InputSearch onChange={setSearch} />
|
||||||
{
|
{
|
||||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||||
|
|||||||
@@ -135,22 +135,25 @@ export default function MemberDiscussionDetail() {
|
|||||||
router.push(`/member/${chooseUser.idUser}`)
|
router.push(`/member/${chooseUser.idUser}`)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{
|
||||||
|
entityUser.role != "user" && entityUser.role != "coadmin" &&
|
||||||
|
<MenuItemRow
|
||||||
|
icon={<MaterialCommunityIcons name="account-remove" color="black" size={25} />}
|
||||||
|
title="Keluarkan"
|
||||||
|
onPress={() => {
|
||||||
|
setModal(false)
|
||||||
|
AlertKonfirmasi({
|
||||||
|
title: 'Konfirmasi',
|
||||||
|
desc: 'Apakah Anda yakin ingin mengeluarkan anggota?',
|
||||||
|
onPress: () => {
|
||||||
|
handleDeleteUser()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
<MenuItemRow
|
}}
|
||||||
icon={<MaterialCommunityIcons name="account-remove" color="black" size={25} />}
|
/>
|
||||||
title="Keluarkan"
|
}
|
||||||
onPress={() => {
|
|
||||||
setModal(false)
|
|
||||||
AlertKonfirmasi({
|
|
||||||
title: 'Konfirmasi',
|
|
||||||
desc: 'Apakah Anda yakin ingin mengeluarkan anggota?',
|
|
||||||
onPress: () => {
|
|
||||||
handleDeleteUser()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</DrawerBottom>
|
</DrawerBottom>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ export default function AddMemberCalendarEvent() {
|
|||||||
}
|
}
|
||||||
<ScrollView
|
<ScrollView
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
|
style={[Styles.h100]}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
data.length > 0 ?
|
data.length > 0 ?
|
||||||
@@ -153,7 +154,6 @@ export default function AddMemberCalendarEvent() {
|
|||||||
style={[Styles.itemSelectModal]}
|
style={[Styles.itemSelectModal]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
!found && onChoose(item.idUser, item.name, item.img)
|
!found && onChoose(item.idUser, item.name, item.img)
|
||||||
onChoose(item.idUser, item.name, item.img)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
@@ -166,7 +166,7 @@ export default function AddMemberCalendarEvent() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{
|
{
|
||||||
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
|
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
|
||||||
}
|
}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export default function CreateCalendarAddMember() {
|
|||||||
}
|
}
|
||||||
<ScrollView
|
<ScrollView
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
|
style={[Styles.h100]}
|
||||||
>
|
>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -304,6 +304,7 @@ export default function DiscussionDetail() {
|
|||||||
bg="white"
|
bg="white"
|
||||||
type="default"
|
type="default"
|
||||||
round
|
round
|
||||||
|
multiline
|
||||||
placeholder="Kirim Komentar"
|
placeholder="Kirim Komentar"
|
||||||
onChange={setKomentar}
|
onChange={setKomentar}
|
||||||
value={komentar}
|
value={komentar}
|
||||||
@@ -323,12 +324,15 @@ export default function DiscussionDetail() {
|
|||||||
entityUser.role == "cosupadmin") &&
|
entityUser.role == "cosupadmin") &&
|
||||||
handleKomentar();
|
handleKomentar();
|
||||||
}}
|
}}
|
||||||
|
style={[
|
||||||
|
Platform.OS == 'android' && Styles.mb15,
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<MaterialIcons
|
<MaterialIcons
|
||||||
name="send"
|
name="send"
|
||||||
size={25}
|
size={25}
|
||||||
style={
|
style={
|
||||||
komentar == "" ||
|
[komentar == "" ||
|
||||||
loadingSend ||
|
loadingSend ||
|
||||||
data?.status == 2 ||
|
data?.status == 2 ||
|
||||||
data?.isActive == false ||
|
data?.isActive == false ||
|
||||||
@@ -336,7 +340,8 @@ export default function DiscussionDetail() {
|
|||||||
entityUser.role == "coadmin") &&
|
entityUser.role == "coadmin") &&
|
||||||
!isMemberDivision)
|
!isMemberDivision)
|
||||||
? Styles.cGray
|
? Styles.cGray
|
||||||
: Styles.cDefault
|
: Styles.cDefault,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import SkeletonContent from "@/components/skeletonContent";
|
|||||||
import Text from "@/components/Text";
|
import Text from "@/components/Text";
|
||||||
import { ConstEnv } from "@/constants/ConstEnv";
|
import { ConstEnv } from "@/constants/ConstEnv";
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
import { apiGetDiscussion } from "@/lib/api";
|
import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { AntDesign, Feather, Ionicons } from "@expo/vector-icons";
|
import { AntDesign, Feather, Ionicons } from "@expo/vector-icons";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
@@ -41,6 +41,30 @@ export default function DiscussionDivision() {
|
|||||||
const [waiting, setWaiting] = useState(false)
|
const [waiting, setWaiting] = useState(false)
|
||||||
const [status, setStatus] = useState<'true' | 'false'>('true')
|
const [status, setStatus] = useState<'true' | 'false'>('true')
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
|
const [isMemberDivision, setIsMemberDivision] = useState(false)
|
||||||
|
const [isAdminDivision, setIsAdminDivision] = useState(false)
|
||||||
|
const entityUser = useSelector((state: any) => state.user)
|
||||||
|
|
||||||
|
async function handleCheckMember() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current));
|
||||||
|
const response = await apiGetDivisionOneFeature({
|
||||||
|
id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "check-member",
|
||||||
|
});
|
||||||
|
|
||||||
|
const response2 = await apiGetDivisionOneFeature({
|
||||||
|
id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "check-admin",
|
||||||
|
});
|
||||||
|
setIsMemberDivision(response.data);
|
||||||
|
setIsAdminDivision(response2.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleLoad(loading: boolean, thisPage: number) {
|
async function handleLoad(loading: boolean, thisPage: number) {
|
||||||
try {
|
try {
|
||||||
@@ -80,6 +104,10 @@ export default function DiscussionDivision() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleCheckMember()
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
handleLoad(false, 1)
|
handleLoad(false, 1)
|
||||||
@@ -101,25 +129,29 @@ export default function DiscussionDivision() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[Styles.p15, { flex: 1 }]}>
|
<View style={[Styles.p15, { flex: 1 }]}>
|
||||||
<View>
|
{
|
||||||
<View style={[Styles.wrapBtnTab]}>
|
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
|
||||||
<ButtonTab
|
<View>
|
||||||
active={status == "false" ? "false" : "true"}
|
<View style={[Styles.wrapBtnTab]}>
|
||||||
value="true"
|
<ButtonTab
|
||||||
onPress={() => { setStatus("true") }}
|
active={status == "false" ? "false" : "true"}
|
||||||
label="Aktif"
|
value="true"
|
||||||
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
|
onPress={() => { setStatus("true") }}
|
||||||
n={2} />
|
label="Aktif"
|
||||||
<ButtonTab
|
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
|
||||||
active={status == "false" ? "false" : "true"}
|
n={2} />
|
||||||
value="false"
|
<ButtonTab
|
||||||
onPress={() => { setStatus("false") }}
|
active={status == "false" ? "false" : "true"}
|
||||||
label="Arsip"
|
value="false"
|
||||||
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
|
onPress={() => { setStatus("false") }}
|
||||||
n={2} />
|
label="Arsip"
|
||||||
|
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
|
||||||
|
n={2} />
|
||||||
|
</View>
|
||||||
|
<InputSearch onChange={setSearch} />
|
||||||
</View>
|
</View>
|
||||||
<InputSearch onChange={setSearch} />
|
}
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import Styles from "@/constants/Styles";
|
|||||||
import {
|
import {
|
||||||
apiDocumentDelete,
|
apiDocumentDelete,
|
||||||
apiDocumentRename,
|
apiDocumentRename,
|
||||||
|
apiGetDivisionOneFeature,
|
||||||
apiGetDocument,
|
apiGetDocument,
|
||||||
apiShareDocument,
|
apiShareDocument,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
@@ -85,6 +86,8 @@ export default function DocumentDivision() {
|
|||||||
const update = useSelector((state: any) => state.dokumenUpdate)
|
const update = useSelector((state: any) => state.dokumenUpdate)
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
const [loadingOpen, setLoadingOpen] = useState(false)
|
const [loadingOpen, setLoadingOpen] = useState(false)
|
||||||
|
const [isMemberDivision, setIsMemberDivision] = useState(false)
|
||||||
|
const entityUser = useSelector((state: any) => state.user)
|
||||||
const [bodyRename, setBodyRename] = useState({
|
const [bodyRename, setBodyRename] = useState({
|
||||||
id: "",
|
id: "",
|
||||||
name: "",
|
name: "",
|
||||||
@@ -93,6 +96,24 @@ export default function DocumentDivision() {
|
|||||||
extension: "",
|
extension: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function handleCheckMember() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current));
|
||||||
|
const response = await apiGetDivisionOneFeature({
|
||||||
|
id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "check-member",
|
||||||
|
});
|
||||||
|
setIsMemberDivision(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleCheckMember()
|
||||||
|
}, [id])
|
||||||
|
|
||||||
async function handleLoad(loading: boolean) {
|
async function handleLoad(loading: boolean) {
|
||||||
try {
|
try {
|
||||||
setLoading(loading)
|
setLoading(loading)
|
||||||
@@ -347,7 +368,7 @@ export default function DocumentDivision() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<HeaderRightDocument path={path} />
|
<HeaderRightDocument path={path} isMember={isMemberDivision} />
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -407,6 +428,7 @@ export default function DocumentDivision() {
|
|||||||
: `${item.name}.${item.extension}`
|
: `${item.name}.${item.extension}`
|
||||||
}
|
}
|
||||||
dateTime={item.createdAt}
|
dateTime={item.createdAt}
|
||||||
|
canChecked={(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision}
|
||||||
onChecked={() => {
|
onChecked={() => {
|
||||||
handleCheckboxChange(index);
|
handleCheckboxChange(index);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export default function DetailTaskDivision() {
|
|||||||
<SectionTanggalTugasTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
<SectionTanggalTugasTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||||
<SectionFileTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
<SectionFileTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||||
<SectionLinkTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
<SectionLinkTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||||
<SectionMemberTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
<SectionMemberTask refreshing={refreshing} isAdminDivision={isAdminDivision} />
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Text from "@/components/Text"
|
|||||||
import { ColorsStatus } from "@/constants/ColorsStatus"
|
import { ColorsStatus } from "@/constants/ColorsStatus"
|
||||||
import { ConstEnv } from "@/constants/ConstEnv"
|
import { ConstEnv } from "@/constants/ConstEnv"
|
||||||
import Styles from "@/constants/Styles"
|
import Styles from "@/constants/Styles"
|
||||||
import { apiDeleteMemberDivision, apiGetDivisionOneDetail, apiUpdateStatusAdminDivision } from "@/lib/api"
|
import { apiDeleteMemberDivision, apiGetDivisionOneDetail, apiGetDivisionOneFeature, apiUpdateStatusAdminDivision } from "@/lib/api"
|
||||||
import { useAuthSession } from "@/providers/AuthProvider"
|
import { useAuthSession } from "@/providers/AuthProvider"
|
||||||
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
|
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router"
|
import { router, Stack, useLocalSearchParams } from "expo-router"
|
||||||
@@ -39,6 +39,7 @@ type PropsMember = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function InformationDivision() {
|
export default function InformationDivision() {
|
||||||
|
const entityUser = useSelector((state: any) => state.user)
|
||||||
const { id } = useLocalSearchParams<{ id: string }>()
|
const { id } = useLocalSearchParams<{ id: string }>()
|
||||||
const [isModal, setModal] = useState(false)
|
const [isModal, setModal] = useState(false)
|
||||||
const { token, decryptToken } = useAuthSession()
|
const { token, decryptToken } = useAuthSession()
|
||||||
@@ -48,6 +49,8 @@ export default function InformationDivision() {
|
|||||||
const update = useSelector((state: any) => state.divisionUpdate)
|
const update = useSelector((state: any) => state.divisionUpdate)
|
||||||
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
|
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [isMemberDivision, setIsMemberDivision] = useState(false)
|
||||||
|
const [isAdminDivision, setIsAdminDivision] = useState(false)
|
||||||
const [dataMemberChoose, setDataMemberChoose] = useState({
|
const [dataMemberChoose, setDataMemberChoose] = useState({
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
@@ -113,12 +116,34 @@ export default function InformationDivision() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleCheckMember() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current));
|
||||||
|
const response = await apiGetDivisionOneFeature({
|
||||||
|
id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "check-member",
|
||||||
|
});
|
||||||
|
|
||||||
|
const response2 = await apiGetDivisionOneFeature({
|
||||||
|
id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "check-admin",
|
||||||
|
});
|
||||||
|
setIsMemberDivision(response.data);
|
||||||
|
setIsAdminDivision(response2.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleLoad(false)
|
handleLoad(false)
|
||||||
}, [refresh, update])
|
}, [refresh, update])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleLoad(true)
|
handleLoad(true)
|
||||||
|
handleCheckMember()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
function handleChooseMember(item: PropsMember) {
|
function handleChooseMember(item: PropsMember) {
|
||||||
@@ -133,7 +158,7 @@ export default function InformationDivision() {
|
|||||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||||
headerTitle: 'Informasi Divisi',
|
headerTitle: 'Informasi Divisi',
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
headerRight: () => <HeaderRightDivisionInfo id={id} active={dataDetail?.isActive} />,
|
headerRight: () => ((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && <HeaderRightDivisionInfo id={id} active={dataDetail?.isActive} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ScrollView style={[Styles.h100]}>
|
<ScrollView style={[Styles.h100]}>
|
||||||
@@ -161,6 +186,7 @@ export default function InformationDivision() {
|
|||||||
<Text style={[Styles.textDefault, Styles.mv05]}>{dataMember.length} Anggota</Text>
|
<Text style={[Styles.textDefault, Styles.mv05]}>{dataMember.length} Anggota</Text>
|
||||||
<View style={[Styles.wrapPaper]}>
|
<View style={[Styles.wrapPaper]}>
|
||||||
{
|
{
|
||||||
|
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
|
||||||
dataDetail?.isActive && (
|
dataDetail?.isActive && (
|
||||||
<BorderBottomItem
|
<BorderBottomItem
|
||||||
onPress={() => { router.push(`/division/${id}/add-member`) }}
|
onPress={() => { router.push(`/division/${id}/add-member`) }}
|
||||||
@@ -188,7 +214,7 @@ export default function InformationDivision() {
|
|||||||
<BorderBottomItem
|
<BorderBottomItem
|
||||||
key={index}
|
key={index}
|
||||||
borderType="bottom"
|
borderType="bottom"
|
||||||
onPress={() => { dataDetail?.isActive && handleChooseMember(item) }}
|
onPress={() => { dataDetail?.isActive && (isAdminDivision || (entityUser.role != "user" && entityUser.role != "coadmin")) && handleChooseMember(item) }}
|
||||||
icon={
|
icon={
|
||||||
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="sm" />
|
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="sm" />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { setFormCreateDivision } from "@/lib/divisionCreate";
|
|||||||
import { setUpdateDivision } from "@/lib/divisionUpdate";
|
import { setUpdateDivision } from "@/lib/divisionUpdate";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { AntDesign } from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
|
import { StackActions, useNavigation } from "@react-navigation/native";
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
||||||
@@ -23,6 +24,7 @@ type Props = {
|
|||||||
|
|
||||||
export default function CreateDivisionAddAdmin() {
|
export default function CreateDivisionAddAdmin() {
|
||||||
const { token, decryptToken } = useAuthSession()
|
const { token, decryptToken } = useAuthSession()
|
||||||
|
const navigation = useNavigation()
|
||||||
const { id } = useLocalSearchParams<{ id: string }>()
|
const { id } = useLocalSearchParams<{ id: string }>()
|
||||||
const [dataOld, setDataOld] = useState<Props[]>([])
|
const [dataOld, setDataOld] = useState<Props[]>([])
|
||||||
const [data, setData] = useState<Props[]>([])
|
const [data, setData] = useState<Props[]>([])
|
||||||
@@ -57,7 +59,8 @@ export default function CreateDivisionAddAdmin() {
|
|||||||
Toast.show({ type: 'small', text1: 'Berhasil membuat divisi', })
|
Toast.show({ type: 'small', text1: 'Berhasil membuat divisi', })
|
||||||
dispatch(setFormCreateDivision({ admin: [], member: [], data: { idGroup: '', name: '', desc: '' } }))
|
dispatch(setFormCreateDivision({ admin: [], member: [], data: { idGroup: '', name: '', desc: '' } }))
|
||||||
dispatch(setUpdateDivision(!updateDivision))
|
dispatch(setUpdateDivision(!updateDivision))
|
||||||
router.replace(`/division/`)
|
navigation.dispatch(StackActions.pop(3))
|
||||||
|
// router.replace(`/division/`)
|
||||||
} else {
|
} else {
|
||||||
Toast.show({ type: 'small', text1: response.message, })
|
Toast.show({ type: 'small', text1: response.message, })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ import { apiEditProfile, apiGetProfile } from "@/lib/api";
|
|||||||
import { setEntities } from "@/lib/entitiesSlice";
|
import { setEntities } from "@/lib/entitiesSlice";
|
||||||
import { useAuthSession } from "@/providers/AuthProvider";
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||||
|
import { useHeaderHeight } from "@react-navigation/elements";
|
||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import { router, Stack } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Image,
|
Image,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Platform,
|
||||||
Pressable,
|
Pressable,
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
@@ -37,6 +40,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function EditProfile() {
|
export default function EditProfile() {
|
||||||
|
const headerHeight = useHeaderHeight()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const entities = useSelector((state: any) => state.entities)
|
const entities = useSelector((state: any) => state.entities)
|
||||||
const { token, decryptToken } = useAuthSession()
|
const { token, decryptToken } = useAuthSession()
|
||||||
@@ -231,116 +235,122 @@ export default function EditProfile() {
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ScrollView style={[Styles.h100]}>
|
<KeyboardAvoidingView
|
||||||
<View style={[Styles.p15]}>
|
style={[Styles.h100]}
|
||||||
<View style={{ justifyContent: "center", alignItems: "center" }}>
|
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||||||
{
|
keyboardVerticalOffset={headerHeight}
|
||||||
selectedImage != undefined ? (
|
>
|
||||||
<Pressable onPress={pickImageAsync}>
|
<ScrollView showsVerticalScrollIndicator={false}>
|
||||||
<Image
|
<View style={[Styles.p15]}>
|
||||||
src={
|
<View style={{ justifyContent: "center", alignItems: "center" }}>
|
||||||
typeof selectedImage === "string"
|
{
|
||||||
? selectedImage
|
selectedImage != undefined ? (
|
||||||
: selectedImage.uri
|
<Pressable onPress={pickImageAsync}>
|
||||||
}
|
<Image
|
||||||
style={[Styles.userProfileBig]}
|
src={
|
||||||
onError={() => { setErrorImg(true) }}
|
typeof selectedImage === "string"
|
||||||
/>
|
? selectedImage
|
||||||
<View style={[Styles.absoluteIconPicker]}>
|
: selectedImage.uri
|
||||||
<MaterialCommunityIcons name="image" color={'white'} size={15} />
|
}
|
||||||
</View>
|
style={[Styles.userProfileBig]}
|
||||||
</Pressable>
|
onError={() => { setErrorImg(true) }}
|
||||||
) : (
|
/>
|
||||||
<Pressable onPress={pickImageAsync}>
|
<View style={[Styles.absoluteIconPicker]}>
|
||||||
<Image
|
<MaterialCommunityIcons name="image" color={'white'} size={15} />
|
||||||
source={errorImg ? require("../../assets/images/user.jpg") : { uri: `${ConstEnv.url_storage}/files/${data?.img}` }}
|
</View>
|
||||||
style={[Styles.userProfileBig]}
|
</Pressable>
|
||||||
onError={() => { setErrorImg(true) }}
|
) : (
|
||||||
/>
|
<Pressable onPress={pickImageAsync}>
|
||||||
<View style={[Styles.absoluteIconPicker]}>
|
<Image
|
||||||
<MaterialCommunityIcons name="image" color={'white'} size={15} />
|
source={errorImg ? require("../../assets/images/user.jpg") : { uri: `${ConstEnv.url_storage}/files/${data?.img}` }}
|
||||||
</View>
|
style={[Styles.userProfileBig]}
|
||||||
</Pressable>
|
onError={() => { setErrorImg(true) }}
|
||||||
)
|
/>
|
||||||
}
|
<View style={[Styles.absoluteIconPicker]}>
|
||||||
|
<MaterialCommunityIcons name="image" color={'white'} size={15} />
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
<SelectForm
|
||||||
|
label="Jabatan"
|
||||||
|
placeholder="Pilih Jabatan"
|
||||||
|
value={choosePosition.label}
|
||||||
|
required
|
||||||
|
onPress={() => {
|
||||||
|
setValChoose(choosePosition.val);
|
||||||
|
setValSelect("position");
|
||||||
|
setSelect(true);
|
||||||
|
}}
|
||||||
|
error={error.position}
|
||||||
|
errorText="Jabatan tidak boleh kosong"
|
||||||
|
/>
|
||||||
|
<InputForm
|
||||||
|
label="NIK"
|
||||||
|
type="numeric"
|
||||||
|
placeholder="NIK"
|
||||||
|
required
|
||||||
|
value={data?.nik}
|
||||||
|
error={error.nik}
|
||||||
|
errorText="NIK Harus 16 Karakter"
|
||||||
|
onChange={val => {
|
||||||
|
validationForm("nik", val)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<InputForm
|
||||||
|
label="Nama"
|
||||||
|
type="default"
|
||||||
|
placeholder="Nama"
|
||||||
|
required
|
||||||
|
value={data?.name}
|
||||||
|
error={error.name}
|
||||||
|
errorText="Nama tidak boleh kosong"
|
||||||
|
onChange={val => {
|
||||||
|
validationForm("name", val)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<InputForm
|
||||||
|
label="Email"
|
||||||
|
type="default"
|
||||||
|
placeholder="Email"
|
||||||
|
required
|
||||||
|
value={data?.email}
|
||||||
|
error={error.email}
|
||||||
|
errorText="Email tidak valid"
|
||||||
|
onChange={val => {
|
||||||
|
validationForm("email", val)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<InputForm
|
||||||
|
label="Nomor Telepon"
|
||||||
|
type="numeric"
|
||||||
|
placeholder="8XX-XXX-XXX"
|
||||||
|
required
|
||||||
|
itemLeft={<Text>+62</Text>}
|
||||||
|
value={data?.phone}
|
||||||
|
error={error.phone}
|
||||||
|
errorText="Nomor Telepon tidak valid"
|
||||||
|
onChange={val => {
|
||||||
|
validationForm("phone", val)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SelectForm
|
||||||
|
label="Jenis Kelamin"
|
||||||
|
placeholder="Pilih Jenis Kelamin"
|
||||||
|
value={chooseGender.label}
|
||||||
|
required
|
||||||
|
onPress={() => {
|
||||||
|
setValChoose(chooseGender.val);
|
||||||
|
setValSelect("gender");
|
||||||
|
setSelect(true);
|
||||||
|
}}
|
||||||
|
error={error.gender}
|
||||||
|
errorText="Jenis Kelamin tidak boleh kosong"
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<SelectForm
|
</ScrollView>
|
||||||
label="Jabatan"
|
</KeyboardAvoidingView>
|
||||||
placeholder="Pilih Jabatan"
|
|
||||||
value={choosePosition.label}
|
|
||||||
required
|
|
||||||
onPress={() => {
|
|
||||||
setValChoose(choosePosition.val);
|
|
||||||
setValSelect("position");
|
|
||||||
setSelect(true);
|
|
||||||
}}
|
|
||||||
error={error.position}
|
|
||||||
errorText="Jabatan tidak boleh kosong"
|
|
||||||
/>
|
|
||||||
<InputForm
|
|
||||||
label="NIK"
|
|
||||||
type="numeric"
|
|
||||||
placeholder="NIK"
|
|
||||||
required
|
|
||||||
value={data?.nik}
|
|
||||||
error={error.nik}
|
|
||||||
errorText="NIK Harus 16 Karakter"
|
|
||||||
onChange={val => {
|
|
||||||
validationForm("nik", val)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<InputForm
|
|
||||||
label="Nama"
|
|
||||||
type="default"
|
|
||||||
placeholder="Nama"
|
|
||||||
required
|
|
||||||
value={data?.name}
|
|
||||||
error={error.name}
|
|
||||||
errorText="Nama tidak boleh kosong"
|
|
||||||
onChange={val => {
|
|
||||||
validationForm("name", val)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<InputForm
|
|
||||||
label="Email"
|
|
||||||
type="default"
|
|
||||||
placeholder="Email"
|
|
||||||
required
|
|
||||||
value={data?.email}
|
|
||||||
error={error.email}
|
|
||||||
errorText="Email tidak valid"
|
|
||||||
onChange={val => {
|
|
||||||
validationForm("email", val)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<InputForm
|
|
||||||
label="Nomor Telepon"
|
|
||||||
type="numeric"
|
|
||||||
placeholder="8XX-XXX-XXX"
|
|
||||||
required
|
|
||||||
itemLeft={<Text>+62</Text>}
|
|
||||||
value={data?.phone}
|
|
||||||
error={error.phone}
|
|
||||||
errorText="Nomor Telepon tidak valid"
|
|
||||||
onChange={val => {
|
|
||||||
validationForm("phone", val)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SelectForm
|
|
||||||
label="Jenis Kelamin"
|
|
||||||
placeholder="Pilih Jenis Kelamin"
|
|
||||||
value={chooseGender.label}
|
|
||||||
required
|
|
||||||
onPress={() => {
|
|
||||||
setValChoose(chooseGender.val);
|
|
||||||
setValSelect("gender");
|
|
||||||
setSelect(true);
|
|
||||||
}}
|
|
||||||
error={error.gender}
|
|
||||||
errorText="Jenis Kelamin tidak boleh kosong"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<ModalSelect
|
<ModalSelect
|
||||||
category={valSelect}
|
category={valSelect}
|
||||||
|
|||||||
@@ -189,7 +189,10 @@ export default function Index() {
|
|||||||
return (
|
return (
|
||||||
<BorderBottomItem
|
<BorderBottomItem
|
||||||
key={index}
|
key={index}
|
||||||
onPress={() => { handleChooseData(item.id, item.name, item.isActive, item.idGroup) }}
|
onPress={() => {
|
||||||
|
entityUser.role != "user" &&
|
||||||
|
handleChooseData(item.id, item.name, item.isActive, item.idGroup)
|
||||||
|
}}
|
||||||
borderType="all"
|
borderType="all"
|
||||||
icon={
|
icon={
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export default function CreateProject() {
|
|||||||
const taskCreate = useSelector((state: any) => state.taskCreate);
|
const taskCreate = useSelector((state: any) => state.taskCreate);
|
||||||
const update = useSelector((state: any) => state.projectUpdate)
|
const update = useSelector((state: any) => state.projectUpdate)
|
||||||
const entityUser = useSelector((state: any) => state.user);
|
const entityUser = useSelector((state: any) => state.user);
|
||||||
|
const userLogin = useSelector((state: any) => state.entities)
|
||||||
const [fileForm, setFileForm] = useState<any[]>([])
|
const [fileForm, setFileForm] = useState<any[]>([])
|
||||||
const [indexDelFile, setIndexDelFile] = useState<number>(0)
|
const [indexDelFile, setIndexDelFile] = useState<number>(0)
|
||||||
const [disableBtn, setDisableBtn] = useState(true)
|
const [disableBtn, setDisableBtn] = useState(true)
|
||||||
@@ -86,7 +87,7 @@ export default function CreateProject() {
|
|||||||
} else {
|
} else {
|
||||||
setError(error => ({ ...error, title: false }))
|
setError(error => ({ ...error, title: false }))
|
||||||
}
|
}
|
||||||
} else if (cat == "task" && hitung > 1) {
|
} else if (cat == "task" && hitung > 2) {
|
||||||
if (taskCreate.length == 0) {
|
if (taskCreate.length == 0) {
|
||||||
setError(error => ({ ...error, task: true }))
|
setError(error => ({ ...error, task: true }))
|
||||||
} else {
|
} else {
|
||||||
@@ -114,6 +115,13 @@ export default function CreateProject() {
|
|||||||
validationForm('task', '');
|
validationForm('task', '');
|
||||||
}, [taskCreate]);
|
}, [taskCreate]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (entityUser.role != "supadmin" && entityUser.role != "developer") {
|
||||||
|
validationForm('group', userLogin.idGroup, userLogin.group);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|||||||
@@ -193,16 +193,19 @@ export default function ListProject() {
|
|||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
<View style={[Styles.mv05]}>
|
<View style={[Styles.mv05]}>
|
||||||
<Text>Filter :
|
{
|
||||||
{
|
entityUser.role != 'cosupadmin' && entityUser.role != 'admin' &&
|
||||||
(entityUser.role == "supadmin" || entityUser.role == "developer") && nameGroup
|
<Text>Filter :
|
||||||
}
|
{
|
||||||
{
|
(entityUser.role == "supadmin" || entityUser.role == "developer") && nameGroup
|
||||||
(entityUser.role == 'user' || entityUser.role == 'coadmin' || entityUser.role == 'cosupadmin')
|
}
|
||||||
? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? 'Kegiatan Saya' : 'Semua Kegiatan'
|
{
|
||||||
: ''
|
(entityUser.role == 'user' || entityUser.role == 'coadmin')
|
||||||
}
|
? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? 'Kegiatan Saya' : 'Semua Kegiatan'
|
||||||
</Text>
|
: ''
|
||||||
|
}
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={[{ flex: 2 }]}>
|
<View style={[{ flex: 2 }]}>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 27 KiB |
@@ -42,7 +42,7 @@ export default function ViewLogin({ onValidate }: Props) {
|
|||||||
return Toast.show({ type: 'small', text1: response.message, position: 'top' })
|
return Toast.show({ type: 'small', text1: response.message, position: 'top' })
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return Toast.show({ type: 'small', text1: 'Terjadi kesalahan', position: 'top' })
|
return Toast.show({ type: 'small', text1: `Terjadi kesalahan, coba lagi`, position: 'top' })
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingLogin(false)
|
setLoadingLogin(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ export default function DiscussionItem({ title, user, date, onPress }: Props) {
|
|||||||
<Pressable style={[Styles.wrapItemDiscussion]} onPress={onPress}>
|
<Pressable style={[Styles.wrapItemDiscussion]} onPress={onPress}>
|
||||||
<View style={[Styles.rowItemsCenter, Styles.mb10]}>
|
<View style={[Styles.rowItemsCenter, Styles.mb10]}>
|
||||||
<Ionicons name="chatbox-ellipses-outline" size={22} color="black" style={Styles.mr10} />
|
<Ionicons name="chatbox-ellipses-outline" size={22} color="black" style={Styles.mr10} />
|
||||||
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
|
<View style={[{flex:1}]}>
|
||||||
|
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={Styles.rowSpaceBetween}>
|
<View style={Styles.rowSpaceBetween}>
|
||||||
<View style={Styles.rowItemsCenter}>
|
<View style={Styles.rowItemsCenter}>
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ export default function HeaderDiscussionGeneral() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
{
|
||||||
|
entityUser.role != "user" && entityUser.role != "coadmin" &&
|
||||||
|
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
||||||
|
}
|
||||||
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
|
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
|
||||||
<View style={Styles.rowItemsCenter}>
|
<View style={Styles.rowItemsCenter}>
|
||||||
<MenuItemRow
|
<MenuItemRow
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { InputForm } from "../inputForm";
|
|||||||
import MenuItemRow from "../menuItemRow";
|
import MenuItemRow from "../menuItemRow";
|
||||||
import ModalFloat from "../modalFloat";
|
import ModalFloat from "../modalFloat";
|
||||||
|
|
||||||
export default function HeaderRightDocument({ path }: { path: string }) {
|
export default function HeaderRightDocument({ path, isMember }: { path: string, isMember: boolean }) {
|
||||||
const [isVisible, setVisible] = useState(false);
|
const [isVisible, setVisible] = useState(false);
|
||||||
const [newFolder, setNewFolder] = useState(false);
|
const [newFolder, setNewFolder] = useState(false);
|
||||||
const { id } = useLocalSearchParams<{ id: string }>();
|
const { id } = useLocalSearchParams<{ id: string }>();
|
||||||
@@ -25,6 +25,7 @@ export default function HeaderRightDocument({ path }: { path: string }) {
|
|||||||
const update = useSelector((state: any) => state.dokumenUpdate)
|
const update = useSelector((state: any) => state.dokumenUpdate)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [loadingFolder, setLoadingFolder] = useState(false)
|
const [loadingFolder, setLoadingFolder] = useState(false)
|
||||||
|
const entityUser = useSelector((state: any) => state.user)
|
||||||
|
|
||||||
async function handleCreateFolder() {
|
async function handleCreateFolder() {
|
||||||
try {
|
try {
|
||||||
@@ -102,11 +103,14 @@ export default function HeaderRightDocument({ path }: { path: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonMenuHeader
|
{
|
||||||
onPress={() => {
|
((entityUser.role != "user" && entityUser.role != "coadmin") || isMember) &&
|
||||||
setVisible(true);
|
<ButtonMenuHeader
|
||||||
}}
|
onPress={() => {
|
||||||
/>
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
<DrawerBottom
|
<DrawerBottom
|
||||||
animation="slide"
|
animation="slide"
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ type Props = {
|
|||||||
checked?: boolean
|
checked?: boolean
|
||||||
onChecked?: () => void
|
onChecked?: () => void
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
|
canChecked?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ItemFile({ category, checked, dateTime, title, onChecked, onPress }: Props) {
|
export default function ItemFile({ category, checked, dateTime, title, onChecked, onPress, canChecked }: Props) {
|
||||||
return (
|
return (
|
||||||
<View style={[Styles.wrapItemBorderBottom]}>
|
<View style={[Styles.wrapItemBorderBottom]}>
|
||||||
<View style={[Styles.rowItemsCenter]}>
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
@@ -43,18 +44,22 @@ export default function ItemFile({ category, checked, dateTime, title, onChecked
|
|||||||
|
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<View style={[Styles.rowSpaceBetween, { flex: 1, alignItems: 'center' }]}>
|
<View style={[Styles.rowSpaceBetween, { flex: 1, alignItems: 'center' }]}>
|
||||||
<Pressable style={[Styles.ml10, {flex:1},]} onPress={onPress}>
|
<Pressable style={[Styles.ml10, { flex: 1 },]} onPress={onPress}>
|
||||||
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
|
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
|
||||||
<Text style={[Styles.textInformation]}>{dateTime}</Text>
|
<Text style={[Styles.textInformation]}>{dateTime}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Pressable onPress={onChecked}>
|
{
|
||||||
{
|
!canChecked ? <></>
|
||||||
checked
|
:
|
||||||
? <MaterialCommunityIcons name="checkbox-marked-circle" size={25} color={'black'} />
|
<Pressable onPress={onChecked}>
|
||||||
: <MaterialCommunityIcons name="checkbox-blank-circle-outline" size={25} color={'#ced4da'} />
|
{
|
||||||
}
|
checked
|
||||||
|
? <MaterialCommunityIcons name="checkbox-marked-circle" size={25} color={'black'} />
|
||||||
|
: <MaterialCommunityIcons name="checkbox-blank-circle-outline" size={25} color={'#ced4da'} />
|
||||||
|
}
|
||||||
|
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export default function DrawerBottom({ isVisible, setVisible, title, children, a
|
|||||||
backdropTransitionInTiming={500}
|
backdropTransitionInTiming={500}
|
||||||
backdropTransitionOutTiming={500}
|
backdropTransitionOutTiming={500}
|
||||||
useNativeDriverForBackdrop={true}
|
useNativeDriverForBackdrop={true}
|
||||||
|
propagateSwipe={true}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
keyboard ?
|
keyboard ?
|
||||||
@@ -62,7 +63,7 @@ export default function DrawerBottom({ isVisible, setVisible, title, children, a
|
|||||||
<MaterialIcons name="close" color="black" size={22} />
|
<MaterialIcons name="close" color="black" size={22} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
<View style={Styles.contentContainer}>
|
<View style={[Styles.contentContainer, { flex: 1 }]}>
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export default function ProjectHome({ refreshing }: { refreshing: boolean }) {
|
|||||||
width={width * 0.8}
|
width={width * 0.8}
|
||||||
height={235}
|
height={235}
|
||||||
data={data}
|
data={data}
|
||||||
loop={true}
|
loop={false}
|
||||||
autoPlay={false}
|
autoPlay={false}
|
||||||
autoPlayReverse={false}
|
autoPlayReverse={false}
|
||||||
pagingEnabled={true}
|
pagingEnabled={true}
|
||||||
|
|||||||
@@ -40,10 +40,15 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
|||||||
<View style={[
|
<View style={[
|
||||||
Styles.inputRoundForm,
|
Styles.inputRoundForm,
|
||||||
itemRight != undefined ? Styles.inputRoundFormRight : Styles.inputRoundFormLeft,
|
itemRight != undefined ? Styles.inputRoundFormRight : Styles.inputRoundFormLeft,
|
||||||
|
multiline && { alignItems: 'flex-end' },
|
||||||
round && Styles.round30,
|
round && Styles.round30,
|
||||||
{ backgroundColor: bg && bg == 'white' ? 'white' : 'transparent' },
|
{ backgroundColor: bg && bg == 'white' ? 'white' : 'transparent' },
|
||||||
error && { borderColor: "red" },
|
error && { borderColor: "red" },
|
||||||
Platform.OS == 'ios' ? { paddingVertical: 10 } : { paddingVertical: 0 },
|
Platform.OS == 'ios' ? { paddingVertical: 10 } : { paddingVertical: 0, minHeight: 40 },
|
||||||
|
{ alignItems: 'center' },
|
||||||
|
multiline
|
||||||
|
? { alignItems: "flex-end" } // multiline: tombol send di bawah
|
||||||
|
: { alignItems: "center" }, // default: tetap di tengah
|
||||||
]}>
|
]}>
|
||||||
{itemRight != undefined ? itemRight : itemLeft}
|
{itemRight != undefined ? itemRight : itemLeft}
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -53,7 +58,14 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
|||||||
keyboardType={type}
|
keyboardType={type}
|
||||||
onChangeText={onChange}
|
onChangeText={onChange}
|
||||||
placeholderTextColor={'gray'}
|
placeholderTextColor={'gray'}
|
||||||
style={[Styles.mh05, { width: width ? lebar * width / 100 : lebar * 0.78, color: 'black' }, Platform.OS == 'ios' ? { paddingVertical: 1 } : { paddingVertical: 5 }]}
|
multiline={multiline}
|
||||||
|
numberOfLines={3}
|
||||||
|
style={[
|
||||||
|
Styles.mh05,
|
||||||
|
multiline && { height: '100%', maxHeight: 100 },
|
||||||
|
{ width: width ? lebar * width / 100 : lebar * 0.78, color: 'black' },
|
||||||
|
Platform.OS == 'ios' ? { paddingVertical: 1, paddingTop: 3 } : { paddingVertical: 0 },
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{error && (<Text style={[Styles.textInformation, Styles.cError, Styles.mt05]}>{errorText}</Text>)}
|
{error && (<Text style={[Styles.textInformation, Styles.cError, Styles.mt05]}>{errorText}</Text>)}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ export default function HeaderMemberList() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
{
|
||||||
|
entityUser.role != "user" &&
|
||||||
|
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
||||||
|
}
|
||||||
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={() => setVisible(false)} title="Menu">
|
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={() => setVisible(false)} title="Menu">
|
||||||
<View style={Styles.rowItemsCenter}>
|
<View style={Styles.rowItemsCenter}>
|
||||||
<MenuItemRow
|
<MenuItemRow
|
||||||
|
|||||||
@@ -30,16 +30,20 @@ export default function HeaderRightProjectList() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<MenuItemRow
|
{
|
||||||
icon={<AntDesign name="filter" color="black" size={25} />}
|
(entityUser.role == "user" || entityUser.role == "coadmin" || entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||||
title="Filter"
|
<MenuItemRow
|
||||||
onPress={() => {
|
icon={<AntDesign name="filter" color="black" size={25} />}
|
||||||
setVisible(false)
|
title="Filter"
|
||||||
setTimeout(() => {
|
onPress={() => {
|
||||||
setFilter(true)
|
setVisible(false)
|
||||||
}, 600)
|
setTimeout(() => {
|
||||||
}}
|
setFilter(true)
|
||||||
/>
|
}, 600)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</DrawerBottom>
|
</DrawerBottom>
|
||||||
<ModalFilter
|
<ModalFilter
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type Props = {
|
|||||||
position: string;
|
position: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SectionMemberTask({ refreshing, isMemberDivision }: { refreshing: boolean, isMemberDivision: boolean }) {
|
export default function SectionMemberTask({ refreshing, isAdminDivision }: { refreshing: boolean, isAdminDivision: boolean }) {
|
||||||
const [isModal, setModal] = useState(false);
|
const [isModal, setModal] = useState(false);
|
||||||
const entityUser = useSelector((state: any) => state.user);
|
const entityUser = useSelector((state: any) => state.user);
|
||||||
const { token, decryptToken } = useAuthSession();
|
const { token, decryptToken } = useAuthSession();
|
||||||
@@ -168,7 +168,7 @@ export default function SectionMemberTask({ refreshing, isMemberDivision }: { re
|
|||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision
|
||||||
?
|
?
|
||||||
<MenuItemRow
|
<MenuItemRow
|
||||||
icon={
|
icon={
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict/>
|
<dict>
|
||||||
|
<key>aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
@@ -1,95 +1,99 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Desa+</string>
|
<string>Desa+</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>$(PRODUCT_NAME)</string>
|
<string>$(PRODUCT_NAME)</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0.2</string>
|
<string>1.0.5</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>myapp</string>
|
<string>myapp</string>
|
||||||
<string>mobiledarmasaba.app</string>
|
<string>mobiledarmasaba.app</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>exp+mobile-darmasaba</string>
|
<string>exp+mobile-darmasaba</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>2</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>12.0</string>
|
<string>12.0</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>NSAllowsLocalNetworking</key>
|
<key>NSAllowsLocalNetworking</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Allow $(PRODUCT_NAME) to access your camera</string>
|
<string>Allow $(PRODUCT_NAME) to access your camera</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Allow $(PRODUCT_NAME) to save photos</string>
|
<string>Allow $(PRODUCT_NAME) to save photos</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Allow $(PRODUCT_NAME) to access your photos</string>
|
<string>Allow $(PRODUCT_NAME) to access your photos</string>
|
||||||
<key>NSUserActivityTypes</key>
|
<key>NSUserActivityTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UIBackgroundModes</key>
|
||||||
<string>SplashScreen</string>
|
<array>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<string>remote-notification</string>
|
||||||
<array>
|
</array>
|
||||||
<string>arm64</string>
|
<key>UILaunchStoryboardName</key>
|
||||||
</array>
|
<string>SplashScreen</string>
|
||||||
<key>UIRequiresFullScreen</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<false/>
|
<array>
|
||||||
<key>UIStatusBarStyle</key>
|
<string>arm64</string>
|
||||||
<string>UIStatusBarStyleDefault</string>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UIRequiresFullScreen</key>
|
||||||
<array>
|
<false/>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<key>UIStatusBarStyle</key>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIStatusBarStyleDefault</string>
|
||||||
</array>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<array>
|
||||||
<array>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
</array>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<array>
|
||||||
</array>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<key>UIUserInterfaceStyle</key>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
<string>Automatic</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
<false/>
|
</array>
|
||||||
</dict>
|
<key>UIUserInterfaceStyle</key>
|
||||||
</plist>
|
<string>Automatic</string>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { getApp, getApps, initializeApp } from '@react-native-firebase/app';
|
import { getApp, getApps, initializeApp } from '@react-native-firebase/app';
|
||||||
import { getMessaging, registerDeviceForRemoteMessages, setAutoInitEnabled } from '@react-native-firebase/messaging';
|
import {
|
||||||
|
getMessaging,
|
||||||
|
getToken as getMessagingToken,
|
||||||
|
setAutoInitEnabled,
|
||||||
|
} from '@react-native-firebase/messaging';
|
||||||
import * as Notifications from 'expo-notifications';
|
import * as Notifications from 'expo-notifications';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { PermissionsAndroid, Platform } from 'react-native';
|
import { PermissionsAndroid, Platform } from 'react-native';
|
||||||
|
|
||||||
// Your Firebase project configuration
|
// Firebase config
|
||||||
const RNfirebaseConfig = {
|
const RNfirebaseConfig = {
|
||||||
apiKey: "AIzaSyB2hbsW91J3oRQx4_jgrCCNY0tNt5-21e8",
|
apiKey: "AIzaSyB2hbsW91J3oRQx4_jgrCCNY0tNt5-21e8",
|
||||||
authDomain: "googleapis.com",
|
authDomain: "googleapis.com",
|
||||||
@@ -15,14 +19,15 @@ const RNfirebaseConfig = {
|
|||||||
databaseURL: "https://mobile-darmasaba-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
databaseURL: "https://mobile-darmasaba-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const initializeFirebase = async () => {
|
const initializeFirebase = async () => {
|
||||||
try {
|
try {
|
||||||
const app = getApps().length ? getApp() : initializeApp(RNfirebaseConfig);
|
const app = getApps().length ? getApp() : initializeApp(RNfirebaseConfig);
|
||||||
const mess = getMessaging(app);
|
const mess = getMessaging(app);
|
||||||
await registerDeviceForRemoteMessages(mess);
|
// await registerDeviceForRemoteMessages(mess);
|
||||||
setAutoInitEnabled(mess, true);
|
// `registerDeviceForRemoteMessages` tidak perlu lagi
|
||||||
return mess
|
await setAutoInitEnabled(mess, true);
|
||||||
|
|
||||||
|
return mess;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize Firebase:', error);
|
console.error('Failed to initialize Firebase:', error);
|
||||||
}
|
}
|
||||||
@@ -31,17 +36,16 @@ const initializeFirebase = async () => {
|
|||||||
export const requestPermission = async () => {
|
export const requestPermission = async () => {
|
||||||
try {
|
try {
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
const cek = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS)
|
const cek = await PermissionsAndroid.check(
|
||||||
|
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
|
||||||
|
);
|
||||||
if (!cek) {
|
if (!cek) {
|
||||||
const granted = await PermissionsAndroid.request(
|
const granted = await PermissionsAndroid.request(
|
||||||
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
|
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
|
||||||
);
|
);
|
||||||
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
return granted === PermissionsAndroid.RESULTS.GRANTED;
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
} else if (Platform.OS === 'ios') {
|
} else if (Platform.OS === 'ios') {
|
||||||
const { status } = await Notifications.requestPermissionsAsync();
|
const { status } = await Notifications.requestPermissionsAsync();
|
||||||
return status === 'granted';
|
return status === 'granted';
|
||||||
@@ -54,10 +58,13 @@ export const requestPermission = async () => {
|
|||||||
export const getToken = async () => {
|
export const getToken = async () => {
|
||||||
try {
|
try {
|
||||||
const mess = await initializeFirebase();
|
const mess = await initializeFirebase();
|
||||||
const token = await mess?.getToken();
|
if (!mess) return null;
|
||||||
|
|
||||||
|
// pakai modular API
|
||||||
|
const token = await getMessagingToken(mess);
|
||||||
return token;
|
return token;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting token:", error);
|
console.error('Error getting token:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,4 +80,4 @@ export const useNotification = () => {
|
|||||||
|
|
||||||
initializeAndSetup();
|
initializeAndSetup();
|
||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|||||||
import CryptoES from "crypto-es";
|
import CryptoES from "crypto-es";
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { createContext, MutableRefObject, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import { createContext, MutableRefObject, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { Platform } from 'react-native';
|
|
||||||
|
|
||||||
const AuthContext = createContext<{
|
const AuthContext = createContext<{
|
||||||
signIn: (arg0: string) => void;
|
signIn: (arg0: string) => void;
|
||||||
@@ -57,13 +56,13 @@ export default function AuthProvider({ children }: { children: ReactNode }): Rea
|
|||||||
const permission = await requestPermission()
|
const permission = await requestPermission()
|
||||||
if (permission) {
|
if (permission) {
|
||||||
try {
|
try {
|
||||||
// COMING SOON
|
// if (Platform.OS === 'android') {
|
||||||
if (Platform.OS === 'android') {
|
const tokenDevice = await getToken()
|
||||||
const tokenDevice = await getToken()
|
const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
|
||||||
const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
|
// }else{
|
||||||
}else{
|
// const tokenDevice = await getToken()
|
||||||
const register = await apiRegisteredToken({ user: hasil, token: "" })
|
// const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -82,13 +81,12 @@ export default function AuthProvider({ children }: { children: ReactNode }): Rea
|
|||||||
const signOut = useCallback(async () => {
|
const signOut = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const hasil = await decryptToken(String(tokenRef.current))
|
const hasil = await decryptToken(String(tokenRef.current))
|
||||||
// COMING SOON
|
// if (Platform.OS === 'android') {
|
||||||
if (Platform.OS === 'android') {
|
const token = await getToken()
|
||||||
const token = await getToken()
|
const response = await apiUnregisteredToken({ user: hasil, token: String(token) })
|
||||||
const response = await apiUnregisteredToken({ user: hasil, token: String(token) })
|
// }else{
|
||||||
}else{
|
// const response = await apiUnregisteredToken({ user: hasil, token: "" })
|
||||||
const response = await apiUnregisteredToken({ user: hasil, token: "" })
|
// }
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||