Initial commit

This commit is contained in:
dina 2025-07-14 12:23:13 +07:00
commit 0854d6baea
115 changed files with 26909 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
expo-env.d.ts
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo
app-example

127
App.js Normal file
View File

@ -0,0 +1,127 @@
import "react-native-gesture-handler";
import React, { useState } from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
// Screens
import SplashScreen from "./screens/SplashScreen";
import Onboarding from "./screens/Onboarding";
import AksesAkun from "./screens/AksesAkun"; // Pastikan ini sudah diimport dengan benar
// import masuk from "./screens/masuk";
// import Home from "./screens/AksesWarga/Home";
import Home from "./screens/AksesWarga/Home";
import EcoMapCoinExchangeScreen from "./screens/AksesWarga/EcoMapCoinExchangeScreen";
import NotifikasiScreen from "./screens/AksesWarga/NotifikasiScreen";
import ProfilScreen from "./screens/AksesWarga/ProfilScreen";
import AksesWargaNavigator from "./Navigation/AksesWargaNavigator";
import AksesAdminNavigator from "./Navigation/AksesAdminNavigator";
import BottomTab from "./Navigation/BottomTab";
import AdminScreen from "./screens/AksesAdmin/AdminScreen";
import masuk from "./screens/masuk";
import BottomNav from "./Navigation/BottomNav";
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
// --- Bottom Tab Navigator ---
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={({ route }) => ({
headerShown: false,
tabBarActiveTintColor: "#1B5E20",
tabBarInactiveTintColor: "#A5D6A7",
tabBarStyle: {
backgroundColor: "#2E7D32",
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
height: 60,
paddingBottom: 5,
},
tabBarLabelStyle: {
fontSize: 12,
fontWeight: "600",
marginBottom: 5,
},
tabBarIcon: ({ focused, color, size }) => {
size = 24;
if (route.name === "Home") {
return (
<Ionicons
name={focused ? "home" : "home-outline"}
size={size}
color={color}
/>
);
} else if (route.name === "EcoMapCoinExchangeScreen") {
return <FontAwesome5 name="coins" size={size} color={color} />;
} else if (route.name === "NotifikasiScreen") {
return (
<Ionicons
name={focused ? "notifications" : "notifications-outline"}
size={size}
color={color}
/>
);
} else if (route.name === "ProfilScreen") {
return (
<MaterialCommunityIcons
name={focused ? "account" : "account-outline"}
size={size}
color={color}
/>
);
}
},
})}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="TukarKoin" component={EcoMapCoinExchangeScreen} />
<Tab.Screen name="Notifikasi" component={NotifikasiScreen} />
<Tab.Screen name="Profil" component={ProfilScreen} />
</Tab.Navigator>
);
}
export default function App() {
// // State untuk menyimpan role yang dipilih
// const [selectedRole, setSelectedRole] = useState(null);
// // State login user
// const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<NavigationContainer>
<Stack.Navigator
initialRouteName="Splash"
screenOptions={{ headerShown: false }}
>
{/* Splash Screen */}
<Stack.Screen name="Splash" component={SplashScreen} />
{/* Onboarding Screen */}
<Stack.Screen name="Onboarding" component={Onboarding} />
<Stack.Screen name="AksesAkun" component={AksesAkun} />
{/* <Stack.Screen name="masuk" component={masuk} /> */}
{/* <Stack.Screen name="Home" component={Home} /> */}
{/* <Stack.Screen
name="Home"
component={BottomTab} // Menampilkan BottomTabNavigator di sini
options={{ headerShown: false }} // Menyembunyikan header jika perlu
/> */}
<Stack.Screen
name="AksesAdminNavigator"
component={AksesAdminNavigator}
/>
<Stack.Screen
name="AksesWargaNavigator"
component={AksesWargaNavigator}
/>
</Stack.Navigator>
</NavigationContainer>
</GestureHandlerRootView>
);
}

47
HomeNavigator.js Normal file
View File

@ -0,0 +1,47 @@
import React from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { NavigationContainer } from "@react-navigation/native";
import HomeNavigator from "./HomeNavigator"; // Import HomeNavigator
import ProfilScreenNavigator from "./ProfilScreenNavigator"; // Import ProfileNavigator
import NotifikasiScreen from "./screens/AksesWarga/NotifikasiScreen";
import EcoMapCoinExchangeScreen from "./screens/AksesWarga/EcoMapCoinExchangeScreen";
const Tab = createBottomTabNavigator();
function App() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="Home">
{/* Tab Home yang akan menggunakan HomeNavigator */}
<Tab.Screen
name="HomeNavigator"
component={HomeNavigator} // Gunakan HomeNavigator di sini
options={{ headerShown: false }}
/>
{/* Tab Profile yang menggunakan ProfileNavigator */}
<Tab.Screen
name="ProfilNavigator"
component={ProfilScreenNavigator}
options={{ headerShown: false }}
/>
{/* Tab Notifikasi */}
<Tab.Screen
name="Notifikasi"
component={NotifikasiScreen}
options={{ headerShown: false }}
/>
{/* Tab EcoMap Coin Exchange */}
<Tab.Screen
name="EcoMapCoinExchange"
component={EcoMapCoinExchangeScreen}
options={{ headerShown: false }}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;

View File

@ -0,0 +1,145 @@
import { createStackNavigator } from "@react-navigation/stack";
import AdminScreen from "../screens/AksesAdmin/AdminScreen";
import MasukAdmin from "../screens/MasukAdmin";
import BottomTabAdmin from "../Navigation/BottomTabAdmin";
import PosterEdukasiScreen from "../screens/AksesAdmin/PosterEdukasiScreen";
import PengaduanSampahScreenAdmin from "../screens/AksesAdmin/PengaduanSampahScreenAdmin";
import BerandaPengaduanAdmin from "../screens/AksesAdmin/BerandaPengaduanAdmin";
import DaftarTPSAdmin from "../screens/AksesAdmin/DaftarTPSAdmin";
import TambahTPS from "../screens/AksesAdmin/TambahTPS";
import EditTPS from "../screens/AksesAdmin/EditTPS";
import KontribusiAdmin from "../screens/AksesAdmin/KontribusiAdmin";
import KontribusiBerhasilAdmin from "../screens/AksesAdmin/KontribusiBerhasilAdmin";
import RiwayatDonasiAdmin from "../screens/AksesAdmin/RiwayatDonasiAdmin";
import DetailDalamProses from "../screens/AksesAdmin/DetailDalamProses";
import DetailVerifikasi from "../screens/AksesAdmin/DetailVerifikasi";
import DetailDitolak from "../screens/AksesAdmin/DetailDitolak";
import Laporan from "../screens/AksesAdmin/Laporan";
import TukarKoin from "../screens/AksesAdmin/TukarKoin";
import NotifikasiAdminScreen from "../screens/AksesAdmin/NotifikasiAdminScreen";
import ProfilAdminScreen from "../screens/AksesAdmin/ProfilAdminScreen";
import EditProfilScreen from "../screens/AksesAdmin/EditProfilScreen";
import DetailPengirimanAdmin from "../screens/AksesAdmin/DetailPengirimanAdmin";
import AksesAkun from "../screens/AksesAkun";
import DaftarBarang from "../screens/AksesAdmin/DaftarBarang";
const Stack = createStackNavigator();
export default function AksesAdminNavigator() {
return (
<Stack.Navigator>
<Stack.Screen
name="admin"
component={AksesAkun}
options={{ headerShown: false }}
/>
<Stack.Screen
name="AdminScreen"
component={AdminScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="BottomTabAdmin"
component={BottomTabAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="PosterEdukasiScreen"
component={PosterEdukasiScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="PengaduanSampahScreenAdmin"
component={PengaduanSampahScreenAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DetailDalamProses"
component={DetailDalamProses}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DetailVerifikasi"
component={DetailVerifikasi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DetailDitolak"
component={DetailDitolak}
options={{ headerShown: false }}
/>
<Stack.Screen
name="BerandaPengaduanAdmin"
component={BerandaPengaduanAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Laporan"
component={Laporan}
options={{ headerShown: false }}
/>
<Stack.Screen
name="TukarKoin"
component={TukarKoin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DaftarBarang"
component={DaftarBarang}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DetailPengirimanAdmin"
component={DetailPengirimanAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="NotifikasiAdminScreen"
component={NotifikasiAdminScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ProfilAdminScreen"
component={ProfilAdminScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="EditProfilScreen"
component={EditProfilScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="KontribusiAdmin"
component={KontribusiAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="KontribusiBerhasilAdmin"
component={KontribusiBerhasilAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DaftarTPSAdmin"
component={DaftarTPSAdmin}
options={{ headerShown: false }}
/>
<Stack.Screen
name="TambahTPS"
component={TambahTPS}
options={{ headerShown: false }}
/>
<Stack.Screen
name="EditTPS"
component={EditTPS}
options={{ headerShown: false }}
/>
<Stack.Screen
name="RiwayatDonasiAdmin"
component={RiwayatDonasiAdmin}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}

View File

@ -0,0 +1,222 @@
import { createStackNavigator } from "@react-navigation/stack";
import Home from "../screens/AksesWarga/Home";
// import AksesAkun from "../screens/AksesAkun";
import masuk from "../screens/masuk";
import BottomNav from "./BottomNav";
import LokasiTerdekat from "../screens/AksesWarga/LokasiTerdekat";
import daftarTPS from "../screens/daftarTPS";
import RiwayatCoinScreen from "../screens/AksesWarga/RiwayatCoinScreen";
import pengaduansampah from "../screens/PengaduanWarga/pengaduansampah";
// import PengaduanSampahScreenAdmin from "../screens/AksesAdmin/PengaduanSampahScreenAdmin";
import misimingguan from "../screens/AksesWarga/misimingguan";
import BerandaPengaduan from "../screens/AksesWarga/BerandaPengaduan";
import KontribusiScreen from "../screens/PengaduanWarga/KontribusiScreen";
import EcoMapCoinExchangeScreen from "../screens/AksesWarga/EcoMapCoinExchangeScreen";
// import NotifikasiScreen from "../screens/AksesAdmin/NotifikasiAdminScreen";
import ProfilScreen from "../screens/AksesWarga/ProfilScreen";
import ProfilNavigation from "../Navigation/ProfilNavigation";
import NotifikasiScreen from "../screens/AksesWarga/NotifikasiScreen";
// import DonasiNavigator from "./DonasiNavigator";
import Donasiberhasil from "../screens/ProfilWarga/DonasiWarga/Donasiberhasil";
import Donasi from "../screens/ProfilWarga/DonasiWarga/Donasi";
import MetodeDonasi from "../screens/ProfilWarga/DonasiWarga/MetodeDonasi";
import KonfirmasiPembayaran from "../screens/ProfilWarga/DonasiWarga/KonfirmasiPembayaran";
import DonasiVerifikasi from "../screens/ProfilWarga/DonasiWarga/DonasiVerifikasi";
// import LoadingScreen from "../screens/PengaduanWarga/LoadingScreen";
import PengaduanBerhasil from "../screens/PengaduanWarga/PengaduanBerhasil";
import KontribusiBerhasil from "../screens/PengaduanWarga/KontribusiBerhasil";
// import BerandaPengaduan from "../screens/AksesWarga/BerandaPengaduan";
// import PengaduanWargaNavigator from "../Navigation/AksesWargaNavigator";
import AksesAkun from "../screens/AksesAkun";
import DaftarNavigation from "../Navigation/DaftarNavigation";
import DaftarBerhasil from "../screens/DaftarBerhasil";
import daftar from "../screens/daftar";
import lupasandi from "../screens/password/lupasandi"; // Halaman lupa sandi
import resetsandi from "../screens/password/InputContact"; // Halaman reset sandi
import notifikasisukses from "../screens/password/notifikasisukses"; // Halaman notifikasi sukses
import InputContact from "../screens/password/InputContact";
import VerifyCode from "../screens/password/VerifyCode";
// import LokasiTerdekat from "../screens/AksesWarga/LokasiTerdekat";
// import daftarTPS from "../screens/daftarTPS";
// import RiwayatCoinScreen from "../screens/AksesWarga/RiwayatCoinScreen";
const Stack = createStackNavigator();
const AkeswargaNavigator = createStackNavigator();
function AkeswargaStack() {
return (
<AkeswargaNavigator.Navigator>
<AkeswargaNavigator.Screen
name="ProfilNavigation"
component={ProfilStack}
/>
</AkeswargaNavigator.Navigator>
);
}
export default function AksesWargaNavigator() {
return (
<Stack.Navigator>
{/* <Stack.Screen
name="AksesAkun"
component={AksesAkun}
options={{ headerShown: false }}
/> */}
<Stack.Screen
name="warga"
component={AksesAkun}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DaftarNavigation"
component={DaftarNavigation}
options={{ headerShown: false }}
/>
<Stack.Screen
name="daftar"
component={daftar}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DaftarBerhasil"
component={DaftarBerhasil}
options={{ headerShown: false }}
/>
<Stack.Screen
name="lupasandi"
component={lupasandi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="InputContact"
component={InputContact}
options={{ headerShown: false }}
/>
<Stack.Screen
name="VerifyCode"
component={VerifyCode}
options={{ headerShown: false }}
/>
<Stack.Screen
name="notifikasisukses"
component={notifikasisukses}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen
name="BottomNav"
component={BottomNav}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LokasiTerdekat"
component={LokasiTerdekat}
options={{ headerShown: false }}
/>
<Stack.Screen
name="daftarTPS"
component={daftarTPS}
options={{ headerShown: false }}
/>
<Stack.Screen
name="RiwayatCoinScreen"
component={RiwayatCoinScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="pengaduansampah"
component={pengaduansampah}
options={{ headerShown: false }}
/>
{/* <Stack.Screen
name="pengaduansampahNavigator"
component={PengaduanWargaNavigator}
options={{ headerShown: false }}
/> */}
{/* <Stack.Screen
name="pengaduansampah"
component={pengaduansampah}
options={{ headerShown: false }}
/> */}
{/* <Stack.Screen
name="LoadingScreen"
component={LoadingScreen}
options={{ headerShown: false }}
/> */}
<Stack.Screen
name="PengaduanBerhasil"
component={PengaduanBerhasil}
options={{ headerShown: false }}
/>
<Stack.Screen
name="misimingguan"
component={misimingguan}
options={{ headerShown: false }}
/>
<Stack.Screen
name="BerandaPengaduan"
component={BerandaPengaduan}
options={{ headerShown: false }}
/>
<Stack.Screen
name="KontribusiScreen"
component={KontribusiScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="KontribusiBerhasil"
component={KontribusiBerhasil}
options={{ headerShown: false }}
/>
<Stack.Screen
name="EcoMapCoinExchangeScreen"
component={EcoMapCoinExchangeScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="NotifikasiScreen"
component={NotifikasiScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ProfilScreen"
component={ProfilScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ProfilNavigation"
component={ProfilNavigation}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Donasi"
component={Donasi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="MetodeDonasi"
component={MetodeDonasi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="KonfirmasiPembayaran"
component={KonfirmasiPembayaran}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DonasiVerifikasi"
component={DonasiVerifikasi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Donasiberhasil"
component={Donasiberhasil}
options={{ headerShown: false }}
/>
{/* <Stack.Screen name="Home" component={Home}options={{ headerShown: false }} /> */}
</Stack.Navigator>
);
}

View File

@ -0,0 +1,30 @@
// import { createStackNavigator } from "@react-navigation/stack";
// import Home from "../screens/AksesWarga/Home";
// import pengaduansampah from "../screens/PengaduanWarga/pengaduansampah";
// import masuk from "../screens/masuk";
// import BerandaPengaduan from "../screens/AksesWarga/BerandaPengaduan";
// import KontribusiScreen from "../screens/PengaduanWarga/KontribusiScreen";
// const Stack = createStackNavigator();
// export default function BerandaPengaduanNav() {
// return (
// <Stack.Navigator>
// <Stack.Screen
// name="Home"
// component={Home}
// options={{ headerShown: false }}
// />
// <Stack.Screen
// name="BerandaPengaduan"
// component={BerandaPengaduan}
// options={{ headerShown: false }}
// />
// <Stack.Screen
// name="KontribusiScreen"
// component={KontribusiScreen}
// options={{ headerShown: false }}
// />
// </Stack.Navigator>
// );
// }

94
Navigation/BottomNav.js Normal file
View File

@ -0,0 +1,94 @@
import React from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
import { Ionicons, FontAwesome5 } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const BottomNav = () => {
const navigation = useNavigation();
return (
<View style={styles.bottomNav}>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("Home")}
>
<Ionicons name="home" size={30} color="#2C6B2F" />
<Text style={styles.navText}>UTAMA</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("EcoMapCoinExchangeScreen")}
>
<FontAwesome5 name="exchange-alt" size={24} color="#2C6B2F" />
<Text style={styles.navText}>TUKAR KOIN</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("NotifikasiScreen")}
>
<View style={styles.notifIconContainer}>
<Ionicons name="notifications-outline" size={24} color="#2C6B2F" />
{/* Ensure the badge text is wrapped in Text component */}
<View style={styles.badge}>
<Text style={styles.badgeText}>1</Text>
</View>
</View>
<Text style={styles.navText}>NOTIFIKASI</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("ProfilNavigation")}
>
<Ionicons name="person-circle-outline" size={24} color="#2C6B2F" />
<Text style={styles.navText}>PROFIL</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
bottomNav: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
width: "100%",
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
navItem: {
flex: 1, // Membuat tiap tombol punya lebar yang sama
alignItems: "center",
padding: 6,
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 5,
marginHorizontal: 5,
},
navText: { color: "#2C6B2F", fontSize: 12, marginTop: 5 },
notifIconContainer: { position: "relative" },
badge: {
position: "absolute",
right: -5,
top: -5,
backgroundColor: "#E74C3C",
borderRadius: 10,
paddingHorizontal: 6,
paddingVertical: 2,
},
badgeText: { color: "#fff", fontSize: 10, fontWeight: "bold" },
});
export default BottomNav;

114
Navigation/BottomTab.js Normal file
View File

@ -0,0 +1,114 @@
import React from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Ionicons } from "@expo/vector-icons";
import { Text, StyleSheet } from "react-native";
// Import screens
import Home from "../screens/AksesWarga/Home";
import EcoMapCoinExchangeScreen from "../screens/AksesWarga/EcoMapCoinExchangeScreen";
import NotifikasiScreen from "../screens/AksesWarga/NotifikasiScreen";
import ProfilScreen from "../screens/AksesWarga/ProfilScreen";
const Tab = createBottomTabNavigator();
export default function bottomtab() {
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={({ route }) => ({
headerShown: false,
tabBarStyle: {
backgroundColor: "#fff", // White background for the tab bar
borderTopWidth: 1,
borderTopColor: "#2C6B2F",
marginBottom: 20,
},
tabBarIcon: ({ focused, color, size }) => {
// Set color to green explicitly
const iconColor = "#2C6B2F"; // Green color for icons
let iconName;
if (route.name === "Home") {
iconName = "home";
} else if (route.name === "EcoMapCoin") {
iconName = "swap-horizontal";
} else if (route.name === "Notifikasi") {
iconName = "notifications-outline";
} else if (route.name === "Profil") {
iconName = "person-circle-outline";
}
// Return an icon component with the green color
return <Ionicons name={iconName} size={size} color={iconColor} />;
},
tabBarLabel: ({ focused, color }) => {
let label;
if (route.name === "Home") {
label = "UTAMA";
} else if (route.name === "EcoMapCoin") {
label = "TUKAR KOIN";
} else if (route.name === "Notifikasi") {
label = "NOTIFIKASI";
} else if (route.name === "Profil") {
label = "PROFIL";
}
return (
<Text style={{ color: "#2C6B2F", fontSize: 12 }}>{label}</Text>
); // Green text color
},
})}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen
name="EcoMapCoin"
component={EcoMapCoinExchangeScreen}
options={{ title: "Tukar Koin" }}
/>
<Tab.Screen
name="Notifikasi"
component={NotifikasiScreen}
options={{ title: "Notifikasi" }}
/>
<Tab.Screen
name="Profil"
component={ProfilScreen}
options={{ title: "Profil" }}
/>
</Tab.Navigator>
);
}
const styles = StyleSheet.create({
bottomNav: {
flexDirection: "row",
justifyContent: "space-around",
paddingVertical: 10,
backgroundColor: "#fff",
borderTopWidth: 1,
borderTopColor: "#2C6B2F",
marginBottom: 0, // Green border
},
navItem: {
alignItems: "center",
},
navText: {
fontSize: 12,
color: "#2C6B2F", // Green text color
},
notifIconContainer: {
position: "relative",
},
badge: {
position: "absolute",
top: -5,
right: -5,
backgroundColor: "red",
borderRadius: 8,
paddingHorizontal: 5,
paddingVertical: 2,
},
badgeText: {
color: "#fff",
fontSize: 10,
},
});

View File

@ -0,0 +1,92 @@
import React from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
import { Ionicons, FontAwesome5 } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const BottomTabAdmin = () => {
const navigation = useNavigation();
return (
<View style={styles.bottomNav}>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("AdminScreen")}
>
<Ionicons name="home" size={30} color="#2C6B2F" />
<Text style={styles.navText}>UTAMA</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("TukarKoin")}
>
<FontAwesome5 name="exchange-alt" size={24} color="#2C6B2F" />
<Text style={styles.navText}>TUKAR KOIN</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("NotifikasiAdminScreen")}
>
<View style={styles.notifIconContainer}>
<Ionicons name="notifications-outline" size={24} color="#2C6B2F" />
{/* Ensure the badge text is wrapped in Text component */}
<View style={styles.badge}>
<Text style={styles.badgeText}>1</Text>
</View>
</View>
<Text style={styles.navText}>NOTIFIKASI</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("ProfilAdminScreen")}
>
<Ionicons name="person-circle-outline" size={24} color="#2C6B2F" />
<Text style={styles.navText}>PROFIL</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
bottomNav: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
width: "100%",
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
navItem: {
flex: 1, // Membuat tiap tombol punya lebar yang sama
alignItems: "center",
padding: 6,
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 5,
marginHorizontal: 5,
},
navText: { color: "#2C6B2F", fontSize: 12, marginTop: 5 },
notifIconContainer: { position: "relative" },
badge: {
position: "absolute",
right: -5,
top: -5,
backgroundColor: "#E74C3C",
borderRadius: 10,
paddingHorizontal: 6,
paddingVertical: 2,
},
badgeText: { color: "#fff", fontSize: 10, fontWeight: "bold" },
});
export default BottomTabAdmin;

View File

@ -0,0 +1,83 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { NavigationContainer } from "@react-navigation/native";
import Masuk from "../screens/masuk"; // Halaman login
import Daftar from "../screens/daftar"; // Halaman daftar
import DaftarBerhasil from "../screens/DaftarBerhasil"; // Halaman pendaftaran berhasil
import LupaSandi from "../screens/password/lupasandi"; // Halaman lupa sandi
import ResetSandi from "../screens/password/InputContact"; // Halaman reset sandi
import NotifikasiSukses from "../screens/password/notifikasisukses"; // Halaman notifikasi sukses
// Membuat Stack Navigators
const Stack = createStackNavigator();
const DaftarStack = createStackNavigator(); // Untuk halaman Daftar
const LupaSandiStack = createStackNavigator(); // Untuk halaman Lupa Sandi
// DaftarSekarangStackScreen: Mengatur navigasi untuk pendaftaran
function DaftarSekarangStackScreen() {
return (
<DaftarStack.Navigator>
<DaftarStack.Screen
name="Daftar"
component={Daftar}
options={{ headerShown: false }}
/>
<DaftarStack.Screen
name="DaftarBerhasil"
component={DaftarBerhasil}
options={{ headerShown: false }}
/>
</DaftarStack.Navigator>
);
}
// LupaKataSandiStackScreen: Mengatur navigasi untuk lupa kata sandi
function LupaKataSandiStackScreen() {
return (
<LupaSandiStack.Navigator>
<LupaSandiStack.Screen
name="LupaSandi"
component={LupaSandi}
options={{ headerShown: false }}
/>
<LupaSandiStack.Screen
name="ResetSandi"
component={ResetSandi}
options={{ headerShown: false }}
/>
<LupaSandiStack.Screen
name="NotifikasiSukses"
component={NotifikasiSukses}
options={{ headerShown: false }}
/>
</LupaSandiStack.Navigator>
);
}
// Navigasi utama untuk Akses Warga
export default function DaftarNavigation() {
return (
<NavigationContainer>
<Stack.Navigator>
{/* Halaman Masuk */}
<Stack.Screen
name="Masuk"
component={Masuk}
options={{ headerShown: false }}
/>
{/* Nested Navigators */}
<Stack.Screen
name="DaftarSekarangStackScreen"
component={DaftarSekarangStackScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LupaKataSandiStackScreen"
component={LupaKataSandiStackScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

View File

@ -0,0 +1,187 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
Image,
TouchableOpacity,
StyleSheet,
ScrollView,
Alert,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
const EditProfileScreen = () => {
// State for profile fields
const [profile, setProfile] = useState({
name: "Okta",
email: "okta@example.com",
phone: "08123456789",
address: "Jl. Raya No. 123, Jakarta",
});
// Function to handle input changes
const handleInputChange = (field, value) => {
setProfile({
...profile,
[field]: value,
});
};
// Function to handle save button click with confirmation
const handleSave = () => {
Alert.alert(
"Konfirmasi Edit Data",
"Apakah Anda yakin ingin mengedit data pribadi?",
[
{
text: "Tidak",
onPress: () => console.log("Edit cancelled"),
style: "cancel",
},
{
text: "Yakin",
onPress: () => {
console.log("Data pribadi berhasil disimpan!");
// Implement save logic here (e.g., save to API or local storage)
},
},
],
{ cancelable: false }
);
};
return (
<ScrollView style={styles.container}>
{/* Header with Back Button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => console.log("Go back")}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>Informasi Pribadi</Text>
</View>
{/* Profile Picture Section */}
<View style={styles.profileImageContainer}>
<Image
source={{
uri: "https://imgv3.fotor.com/images/gallery/a-woman-linkedin-picture-with-grey-background-made-by-LinkedIn-Profile-Picture-Maker.jpg",
}} // Placeholder, replace with real profile picture
style={styles.profileImage}
/>
<TouchableOpacity style={styles.changeImageButton}>
<Text style={styles.changeImageText}>Ubah Foto Profil</Text>
</TouchableOpacity>
</View>
{/* Input Fields for Profile Information */}
<View style={styles.formSection}>
<TextInput
style={styles.inputField}
value={profile.name}
placeholder="Nama"
onChangeText={(text) => handleInputChange("name", text)}
/>
<TextInput
style={styles.inputField}
value={profile.email}
placeholder="Email"
onChangeText={(text) => handleInputChange("email", text)}
/>
<TextInput
style={styles.inputField}
value={profile.phone}
placeholder="No. HP"
onChangeText={(text) => handleInputChange("phone", text)}
/>
<TextInput
style={styles.inputField}
value={profile.address}
placeholder="Alamat"
onChangeText={(text) => handleInputChange("address", text)}
/>
</View>
{/* Save Button */}
<TouchableOpacity style={styles.saveButton} onPress={handleSave}>
<Text style={styles.saveButtonText}>Simpan</Text>
</TouchableOpacity>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f9f9f9",
paddingHorizontal: 20,
paddingTop: 30,
},
header: {
flexDirection: "row", // Align back button and title in one row
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
},
profileImageContainer: {
alignItems: "center",
marginBottom: 30,
},
profileImage: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 10,
},
changeImageButton: {
backgroundColor: "#dcdcdc",
paddingVertical: 5,
paddingHorizontal: 20,
borderRadius: 5,
},
changeImageText: {
color: "#333",
fontSize: 14,
},
formSection: {
marginBottom: 30,
},
inputField: {
backgroundColor: "#fff",
padding: 15,
borderRadius: 8,
marginBottom: 15,
fontSize: 16,
borderColor: "#ddd",
borderWidth: 1,
},
saveButton: {
backgroundColor: "#2D572C", // Green color
paddingVertical: 12,
borderRadius: 8,
alignItems: "center",
},
saveButtonText: {
fontSize: 16,
color: "#fff",
fontWeight: "bold",
},
logoutButtonText: {
fontSize: 16,
color: "#fff",
fontWeight: "bold",
},
});
export default EditProfileScreen;

View File

@ -0,0 +1,23 @@
import React, { Component } from "react";
import { Text } from "react-native";
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error("Error caught by Error Boundary:", error);
}
render() {
if (this.state.hasError) {
return <Text>Error Occurred!</Text>;
}
return this.props.children;
}
}
export default ErrorBoundary;

View File

@ -0,0 +1,56 @@
import { createStackNavigator } from "@react-navigation/stack";
import Home from "../screens/AksesWarga/Home";
import pengaduansampah from "../screens/PengaduanWarga/pengaduansampah";
import masuk from "../screens/masuk";
import LoadingScreen from "../screens/PengaduanWarga/LoadingScreen";
import PengaduanBerhasil from "../screens/PengaduanWarga/PengaduanBerhasil";
import BerandaPengaduan from "../screens/AksesWarga/BerandaPengaduan";
const Stack = createStackNavigator();
// Navigator untuk Pengaduan Warga
function PengaduanWargaStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="pengaduansampah"
component={pengaduansampah}
options={{ headerShown: false }}
/>
{/* <Stack.Screen
name="LoadingScreen"
component={LoadingScreen}
options={{ headerShown: false }}
/> */}
<Stack.Screen
name="PengaduanBerhasil"
component={PengaduanBerhasil}
options={{ headerShown: false }}
/>
<Stack.Screen
name="BerandaPengaduan"
component={BerandaPengaduan}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
// Navigator utama untuk Akses Warga
export default function AksesWargaNavigator() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
{/* Di sini kita bisa menambahkan PengaduanWargaStack sebagai nested navigator */}
<Stack.Screen
name="PengaduanWargaNavigator"
component={PengaduanWargaStackScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}

View File

@ -0,0 +1,133 @@
import { createStackNavigator } from "@react-navigation/stack";
import { NavigationContainer } from "@react-navigation/native";
import Home from "../screens/AksesWarga/Home";
// import AksesAkun from "../screens/AksesAkun";
import masuk from "../screens/masuk";
// import bottomtab from "./BottomTab";
import LokasiTerdekat from "../screens/AksesWarga/LokasiTerdekat";
import daftarTPS from "../screens/daftarTPS";
import RiwayatCoinScreen from "../screens/AksesWarga/RiwayatCoinScreen";
import pengaduansampah from "../screens/PengaduanWarga/pengaduansampah";
import PengaduanSampahScreenAdmin from "../screens/AksesAdmin/PengaduanSampahScreenAdmin";
import misimingguan from "../screens/AksesWarga/misimingguan";
import BerandaPengaduan from "../screens/AksesWarga/BerandaPengaduan";
import KontribusiScreen from "../screens/PengaduanWarga/KontribusiScreen";
import EcoMapCoinExchangeScreen from "../screens/AksesWarga/EcoMapCoinExchangeScreen";
import NotifikasiScreen from "../screens/AksesAdmin/NotifikasiAdminScreen";
import ProfilScreen from "../screens/AksesWarga/ProfilScreen";
import DetailPengaduan from "../screens/PengaduanWarga/DetailPengaduan";
import StatusPengirimanScreen from "../screens/ProfilWarga/StatusPengiriman/StatusPengirimanScreen";
import Donasi from "../screens/ProfilWarga/DonasiWarga/Donasi";
import InformasiPribadi from "../screens/ProfilWarga/InformasiPribadi/InformasiPribadi";
import EditInformasiPribadi from "../screens/ProfilWarga/InformasiPribadi/EditInformasiPribadi";
import DetailPengiriman from "../screens/ProfilWarga/StatusPengiriman/DetailPengiriman";
import Donasiberhasil from "../screens/ProfilWarga/DonasiWarga/Donasiberhasil";
import StatusPengaduan from "../screens/ProfilWarga/StatusPengaduan/StatusPengaduan";
// import Donasi from "../screens/ProfilWarga/DonasiWarga/Donasi";
import MetodeDonasi from "../screens/ProfilWarga/DonasiWarga/MetodeDonasi";
import KonfirmasiPembayaran from "../screens/ProfilWarga/DonasiWarga/KonfirmasiPembayaran";
import DonasiVerifikasi from "../screens/ProfilWarga/DonasiWarga/DonasiVerifikasi";
// import LokasiTerdekat from "../screens/AksesWarga/LokasiTerdekat";
// import daftarTPS from "../screens/daftarTPS";
// import RiwayatCoinScreen from "../screens/AksesWarga/RiwayatCoinScreen";
const Stack = createStackNavigator();
const ProfilNavigator = createStackNavigator();
function StatusPengaduanStack() {
return (
<ProfilNavigator.Navigator>
<ProfilNavigator.Screen
name="StatusPengaduan"
component={StatusPengaduan}
options={{ headerShown: false }}
/>
</ProfilNavigator.Navigator>
);
}
function InformasiPribadiStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="InformasiPribadi"
component={InformasiPribadi}
options={{ headerShown: false }}
/>
<Stack.Screen
name="EditInformasiPribadi"
component={EditInformasiPribadi}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
function StatusPenukaranKoinStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="StatusPengirimanScreen"
component={StatusPengirimanScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DetailPengiriman"
component={DetailPengiriman}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
function DonasiStackScreen() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Donasi" component={Donasi} />
<Stack.Screen name="MetodeDonasi" component={MetodeDonasi} />
<Stack.Screen
name="KonfirmasiPembayaran"
component={KonfirmasiPembayaran}
/>
<Stack.Screen name="DonasiVerifikasi" component={DonasiVerifikasi} />
<Stack.Screen name="Donasiberhasil" component={Donasiberhasil} />
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
);
}
// Navigator utama untuk Akses Warga
export default function ProfilNavigation() {
return (
<Stack.Navigator>
{/* <Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/> */}
<Stack.Screen
name="ProfilScreen"
component={ProfilScreen}
options={{ headerShown: false }}
/>
{/* Di sini kita bisa menambahkan PengaduanWargaStack sebagai nested navigator */}
<Stack.Screen
name="InformasiPribadiStackScreen"
component={InformasiPribadiStackScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="StatusPenukaranKoinStackScreen"
component={StatusPenukaranKoinStackScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="DonasiStackScreen"
component={DonasiStackScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="StatusPengaduanStack"
component={StatusPengaduanStack}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}

35
ProfilScreenNavigator.js Normal file
View File

@ -0,0 +1,35 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import ProfilScreen from "./screens/AksesWarga/ProfilScreen";
// Pastikan StatusPengirimanScreen sudah diimpor jika kamu ingin menggunakannya
import StatusPengirimanScreen from "./screens/ProfilWarga/StatusPengiriman/StatusPengirimanScreen";
import Donasi from "./screens/ProfilWarga/DonasiWarga/Donasi";
const Stack = createStackNavigator();
function ProfilScreenNavigator() {
return (
<Stack.Navigator>
{/* Layar Utama Profile */}
<Stack.Screen
name="ProfilScreen"
component={ProfilScreen}
options={{ headerShown: false }}
/>
{/* Layar-Layar Detail di dalam Profile */}
<Stack.Screen
name="StatusPengirimanScreen"
component={StatusPengirimanScreen}
options={{ title: "Status Penukaran Koin" }}
/>
<Stack.Screen
name="Donasi"
component={Donasi}
options={{ title: "Donasi" }}
/>
</Stack.Navigator>
);
}
export default ProfilScreenNavigator;

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# Welcome to your Expo app 👋
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
## Get started
1. Install dependencies
```bash
npm install
```
2. Start the app
```bash
npx expo start
```
In the output, you'll find options to open the app in a
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
## Get a fresh project
When you're ready, run:
```bash
npm run reset-project
```
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
## Learn more
To learn more about developing your project with Expo, look at the following resources:
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
## Join the community
Join our community of developers creating universal apps.
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.

52
app.json Normal file
View File

@ -0,0 +1,52 @@
{
"expo": {
"doctor": {
"reactNativeDirectoryCheck": {
"listUnknownPackages": false,
"name": "yakinbisa",
"slug": "yakinbisa",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"platforms": [
"ios",
"android"
],
"android": {
"jsEngine": "hermes",
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
}
}
},
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
[
"expo-splash-screen",
{
"image": "./assets/images/splash-icon.png",
"imageWidth": 200,
"resizeMode": "contain",
"backgroundColor": "#ffffff"
}
],
"expo-font",
"expo-router"
],
"experiments": {
"typedRoutes": true
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

BIN
assets/images/alatmakan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
assets/images/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assets/images/botol1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
assets/images/botol2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
assets/images/daftar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
assets/images/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/foto2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
assets/images/foto3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
assets/images/headerbg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
assets/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
assets/images/koin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
assets/images/poster1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
assets/images/poster2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/images/poster3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets/images/sampah.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/tas2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
assets/images/warga.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

0
npm Normal file
View File

12591
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

65
package.json Normal file
View File

@ -0,0 +1,65 @@
{
"name": "yakinbisa",
"version": "1.0.0",
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"test": "jest --watchAll",
"lint": "expo lint"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@expo/vector-icons": "^14.1.0",
"@react-native-picker/picker": "2.11.0",
"@react-navigation/bottom-tabs": "^7.3.13",
"@react-navigation/native": "^7.1.9",
"@react-navigation/stack": "^7.3.2",
"expo": "^53.0.11",
"expo-blur": "~14.1.5",
"expo-camera": "~16.1.7",
"expo-checkbox": "~4.1.4",
"expo-constants": "~17.1.6",
"expo-font": "~13.3.1",
"expo-haptics": "~14.1.4",
"expo-image-picker": "~16.1.4",
"expo-linear-gradient": "~14.1.5",
"expo-linking": "~7.1.5",
"expo-location": "~18.1.5",
"expo-media-library": "~17.1.7",
"expo-print": "~14.1.4",
"expo-router": "~5.0.7",
"expo-splash-screen": "^0.30.9",
"expo-status-bar": "~2.2.3",
"expo-symbols": "^0.4.5",
"expo-system-ui": "~5.0.8",
"expo-web-browser": "~14.1.6",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-native": "^0.79.3",
"react-native-calendars": "^1.1312.0",
"react-native-chart-kit": "^6.12.0",
"react-native-gesture-handler": "~2.24.0",
"react-native-google-places-autocomplete": "^2.5.7",
"react-native-maps": "1.20.1",
"react-native-reanimated": "~3.17.4",
"react-native-reanimated-carousel": "^4.0.2",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-svg": "15.11.2",
"react-native-vector-icons": "^10.2.0",
"react-native-web": "^0.20.0",
"expo-av": "~15.1.6"
},
"devDependencies": {
"@babel/core": "^7.26.0",
"jest": "~29.7.0",
"jest-expo": "~53.0.7",
"react-test-renderer": "18.3.1"
},
"private": true
}

View File

@ -0,0 +1,473 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ImageBackground,
Dimensions,
Image,
ScrollView,
} from "react-native";
import {
Ionicons,
FontAwesome5,
MaterialCommunityIcons,
} from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import BottomTabAdmin from "../../Navigation/BottomTabAdmin";
import { LineChart } from "react-native-chart-kit";
const { width, height } = Dimensions.get("window");
const AdminScreen = () => {
const navigation = useNavigation();
const [activeSlide, setActiveSlide] = useState(0);
const data = {
labels: ["Jan", "Feb", "Mar", "Apr", "May"], // Label untuk bulan
datasets: [
{
data: [5000000, 7000000, 4000000, 8000000, 6000000], // Data donasi per bulan
strokeWidth: 1, // Lebar garis
},
],
};
const handleNext = () => {
navigation.navigate(""); // Add the name of the screen to navigate
};
return (
<View style={styles.container}>
<ImageBackground
source={require("../../assets/images/bg.png")}
style={styles.backgroundImage}
>
{/* <Text style={styles.date}>05 Mei 2025</Text> */}
{/* Profile Section */}
<ScrollView contentContainerStyle={styles.scrollContainer}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://shanibacreative.com/wp-content/uploads/2022/10/SCI-0801220002_7-1280x1920.jpeg",
}} // Replace with your image URL
style={styles.profileImage}
/>
<Text style={styles.greetingnama}>
Halooo Dina {"\n"}
<Text style={styles.subtitle}>
Kebersihan Lingkungan Wajib Terjaga!
</Text>
</Text>
<Text style={styles.subtitle}></Text>
{/* <Text style={styles.greetingnama}>
Dinas Lingkungan Hidup{" "}
<Ionicons name="checkmark-circle" size={18} color="green" />
</Text> */}
</View>
{/* <View style={styles.header}> */}
<Text style={styles.subtitle}></Text>
<View style={styles.coinRow}>
<View style={styles.coinInfo}>
<View style={styles.coinBox}>
<Text style={styles.coinLabel}>JUMLAH DONASI</Text>
<View style={styles.coinValueRow}>
<Text style={styles.coinText}>Rp. 5.870.000</Text>
</View>
<Text style={styles.noCoinText}>Donasi dalam satu tahun</Text>
<TouchableOpacity
style={styles.historyButton}
onPress={() => navigation.navigate("RiwayatDonasiAdmin")}
>
<Text style={styles.historyButtonText}>RIWAYAT DONASI</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.coinInfo}>
<View style={styles.coinBox}>
<Text style={styles.coinLabel}>PENGELUARAN</Text>
<View style={styles.coinValueRow}>
<Text style={styles.coinText}>Rp. 3.270.000</Text>
</View>
<Text style={styles.noCoinText}>
Pengeluaran dalam satu bulan
</Text>
<TouchableOpacity
style={styles.historyButton}
onPress={() => navigation.navigate("RiwayatDonasiAdmin")}
>
<Text style={styles.historyButtonText}>
RIWAYAT PENGELUARAN
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.statsContainer}>
<View style={styles.statBox}>
<Text style={styles.statLabel}>Pengaduan</Text>
<Text style={styles.statValue}>102</Text>
</View>
<View style={styles.statBox}>
<Text style={styles.statLabel}>TPS di Nganjuk</Text>
<Text style={styles.statValue}>52</Text>
</View>
</View>
</View>
<TouchableOpacity
style={styles.reportButton}
onPress={() => navigation.navigate("BerandaPengaduanAdmin")}
>
<Text style={styles.reportButtonText}>BERANDA PENGADUAN</Text>
</TouchableOpacity>
<View style={styles.menuContainer}>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("DaftarTPSAdmin")}
>
<Ionicons
name="bookmarks"
size={40}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>TPS di Nganjuk</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("Laporan")}
>
<MaterialCommunityIcons
name="file-document"
size={50}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>Laporan</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("PosterEdukasiScreen")}
>
<FontAwesome5
name="chalkboard-teacher"
size={38}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>Poster Edukasi</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("PengaduanSampahScreenAdmin")}
>
<FontAwesome5
name="exclamation-triangle"
size={40}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>Pengaduan Sampah</Text>
</TouchableOpacity>
</View>
<View style={styles.chartContainer}>
<Text style={styles.chartTitle}>Grafik Donasi Bulanan</Text>
<LineChart
data={data}
width={width - 40} // Mengatur lebar grafik
height={220} // Mengatur tinggi grafik
chartConfig={{
backgroundColor: "#000",
backgroundGradientFrom: "#2C6B2F",
backgroundGradientTo: "#000",
decimalPlaces: 0, // Tidak ada angka desimal pada grafik
color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
style: {
borderRadius: 16,
marginBottom: 40,
},
}}
style={styles.chartStyle}
/>
<Text style={styles.chartTitlebawah}>Grafik Donasi Bulanan</Text>
</View>
</ScrollView>
</ImageBackground>
<BottomTabAdmin />
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#2C6B2F", paddingTop: 20 },
scrollContainer: {
flexGrow: 1, // This ensures the ScrollView can expand to take up the remaining space
paddingHorizontal: 10,
backgroundColor: "#fff",
justifyContent: "flex-start",
// alignItems: "center",
borderBottomLeftRadius: 30,
borderTopStartRadius: 50,
borderBottomRightRadius: 30,
borderTopRightRadius: 50,
paddingBottom: 10,
marginTop: 170,
marginBottom: 150,
borderWidth: 1,
borderColor: "#cdcdcd", // Reduce this padding for better scrolling
},
chartContainer: {
paddingHorizontal: 20,
marginVertical: 20,
marginBottom: 20, // Reduced to avoid pushing the content down
},
profileContainer: {
flexDirection: "row",
alignItems: "flex-start",
marginBottom: 20,
paddingHorizontal: 20,
},
profileImage: {
width: 50,
height: 50,
borderRadius: 50,
marginRight: 10,
marginTop: 30,
},
chartTitle: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 10,
},
chartTitlebawah: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 10,
},
chartStyle: {
borderRadius: 16,
marginBottom: 200,
},
header: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
paddingHorizontal: 20,
backgroundColor: "#fff",
borderBottomLeftRadius: 30,
borderTopStartRadius: 50,
borderBottomRightRadius: 30,
borderTopRightRadius: 50,
paddingBottom: 50,
marginBottom: 50,
marginTop: 10,
},
date: {
fontSize: 18,
color: "#fff",
paddingHorizontal: 20,
marginBottom: 5,
alignItems: "center",
},
greeting: {
fontSize: 22,
fontWeight: "bold",
marginTop: 20,
color: "#000",
paddingHorizontal: 90,
// alignItems: "center",
// justifyContent: "center",
},
greetingnama: {
fontSize: 22,
fontWeight: "bold",
marginTop: 30,
marginLeft: -10,
color: "#000",
paddingHorizontal: 20,
flexDirection: "column",
},
subtitle: {
fontSize: 15,
color: "#000",
fontWeight: "500",
paddingHorizontal: 70,
marginBottom: -30,
marginTop: 5,
marginLeft: 20,
// justifyContent: "center",
},
coinRow: {
flexDirection: "column",
justifyContent: "flex-start",
alignItems: "center",
paddingHorizontal: 20,
marginTop: 0,
},
coinInfo: { alignItems: "flex-start" },
coinLabel: {
fontSize: 18,
fontWeight: "700",
color: "#333",
marginBottom: 0,
marginLeft: -100,
},
coinBox: {
marginVertical: 10,
backgroundColor: "#fff",
paddingHorizontal: 130,
paddingVertical: 15,
borderRadius: 20,
flexDirection: "column",
alignItems: "flex-start",
elevation: 1,
borderWidth: 1,
borderColor: "#aaa",
position: "relative",
marginLeft: -5,
},
coinValueRow: { flexDirection: "row", alignItems: "center", marginTop: 0 },
coinText: {
fontSize: 30,
fontWeight: "bold",
color: "#333",
textAlign: "left",
marginLeft: -100,
marginBottom: 10,
},
noCoinText: {
fontSize: 12,
color: "#aaa",
marginTop: 0,
marginBottom: -5,
textAlign: "left",
marginLeft: -100,
},
statsContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginVertical: 0,
alignContent: "space-between",
padding: 0,
},
statBox: {
backgroundColor: "#fff",
padding: 15,
borderRadius: 15,
width: "30%",
alignItems: "center",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 8,
borderWidth: 0.5,
justifyContent: "space-between",
marginRight: 12,
marginTop: 10,
},
statLabel: {
fontSize: 12,
justifyContent: "center",
color: "black",
alignItems: "center",
fontWeight: "600",
},
statValue: {
fontSize: 25,
fontWeight: "bold",
color: "#000",
},
historyButton: {
position: "absolute",
backgroundColor: "#2C6B2F",
borderColor: "#000",
paddingVertical: 12,
paddingHorizontal: 10,
borderRadius: 20,
top: -6,
right: 10,
marginTop: 20,
alignItems: "center",
justifyContent: "center",
width: "110%",
elevation: 1,
},
historyButtonText: {
fontSize: 12,
fontWeight: "bold",
color: "#fff",
textAlign: "center",
},
reportButton: {
backgroundColor: "#fff",
paddingVertical: 10,
paddingHorizontal: 10,
borderRadius: 20,
// alignItems: "center",
justifyContent: "center",
borderWidth: 0.5,
borderColor: "#000",
width: "80%",
marginTop: 15,
paddingLeft: 5,
padding: 15,
elevation: 2,
marginLeft: 40,
},
reportButtonText: {
fontSize: 16,
color: "#000",
fontWeight: "bold",
textAlign: "center",
padding: 5,
},
menuImage: {
width: 50,
height: 50,
marginLeft: 3,
marginBottom: 5,
marginTop: 10,
justifyContent: "center",
},
menuContainer: {
marginTop: 5,
marginRight: 5,
marginLeft: 12,
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-evenly",
paddingRight: 15,
},
menuItem: {
width: "20%",
alignItems: "center",
marginVertical: 5,
padding: 10,
borderWidth: 0,
borderColor: "#fff",
borderRadius: 25,
backgroundColor: "#fff",
elevation: 2,
},
menuText: {
fontSize: 12,
fontWeight: "500",
color: "#333",
marginTop: 0,
textAlign: "center",
},
});
export default AdminScreen;

View File

@ -0,0 +1,217 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Image } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const BerandaPengaduanAdmin = () => {
const navigation = useNavigation();
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("AdminScreen")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.headerTitle}>BERANDA PENGADUAN</Text>
</View>
{/* First Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Johan Okta Pangestu</Text>
</View>
<Text style={styles.time}>03/01/2025 10.12 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Sedang diverifikasi</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah numpuk di depan masjid - JI Letjen Sparman
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.arenalte.com/uploads/2019/07/sampah.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://www.storypick.com/wp-content/uploads/2019/06/waste.png",
}}
style={styles.reportImage}
/>
</View>
</View>
{/* Second Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar2.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Jihan Pangesti</Text>
</View>
<Text style={styles.time}>03/01/2025 10.12 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Dalam Proses</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah berserakan di Pasar Lama - JI. Sukarno, Nganjuk
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-97714168,imgsize-1547670,width-400,resizemode-4/97714168.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-87155572,imgsize-1511223,width-400,resizemode-4/87155572.jpg",
}}
style={styles.reportImage}
/>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 40,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
headerTitle: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
reportContainer: {
marginBottom: 20,
padding: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
borderColor: "#000",
},
reportHeader: {
flexDirection: "row",
justifyContent: "space-between",
paddingBottom: 10,
},
profileContainer: {
flexDirection: "row",
alignItems: "center",
},
profileImage: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 10,
},
reporterName: {
fontSize: 16,
fontWeight: "bold",
},
time: {
fontSize: 14,
color: "#555",
},
statusButton: {
backgroundColor: "#DDD",
borderRadius: 8,
paddingVertical: 5,
paddingHorizontal: 5,
marginVertical: 8,
alignItems: "center",
width: "32%",
borderWidth: 0.5,
},
reportStatus: {
color: "#000",
fontSize: 14,
},
reportDescription: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
reportNote: {
fontSize: 14,
color: "#000",
marginBottom: 12,
},
imageContainer: {
flexDirection: "row",
justifyContent: "flex-start",
marginBottom: 12,
},
reportImage: {
width: 100,
height: 100,
borderRadius: 8,
marginRight: 5,
marginLeft: 5,
},
contributeButton: {
backgroundColor: "#2D572C",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
contributeText: {
color: "#fff",
fontSize: 16,
},
coinText: {
color: "#fff",
fontSize: 14,
},
});
export default BerandaPengaduanAdmin;

View File

@ -0,0 +1,352 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
Image,
ScrollView,
StyleSheet,
Alert,
} from "react-native";
import * as ImagePicker from "expo-image-picker"; // import image picker
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const DaftarBarang = () => {
const navigation = useNavigation();
const [items, setItems] = useState([
{
id: 1,
name: "Botol Minum",
coin: 300,
image: require("../../assets/images/botol1.png"),
},
{
id: 2,
name: "Botol Minum Anak",
coin: 350,
image: require("../../assets/images/botol2.png"),
},
]);
const [isEditing, setIsEditing] = useState(false);
const [formItem, setFormItem] = useState({
id: null,
name: "",
coin: "",
image: null,
});
const pickImage = async () => {
// Minta izin akses galeri
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
Alert.alert(
"Izin Ditolak",
"Izin akses galeri dibutuhkan untuk memilih foto"
);
return;
}
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
});
if (!result.canceled) {
setFormItem({ ...formItem, image: { uri: result.assets[0].uri } });
}
};
const handleEdit = (item) => {
setFormItem(item);
setIsEditing(true);
};
const handleAddItem = () => {
setFormItem({ id: null, name: "", coin: "", image: null });
setIsEditing(true);
};
const handleSubmit = () => {
if (formItem.name === "" || formItem.coin === "") {
Alert.alert("Error", "Nama dan koin wajib diisi");
return;
}
if (formItem.id) {
// Edit
setItems(items.map((i) => (i.id === formItem.id ? { ...formItem } : i)));
} else {
// Tambah
setItems([
...items,
{
...formItem,
id: Date.now(),
image: formItem.image
? formItem.image
: require("../../assets/images/botol1.png"),
},
]);
}
setIsEditing(false);
};
const handleDelete = (id) => {
Alert.alert("Konfirmasi", "Apakah Anda yakin ingin menghapus item ini?", [
{
text: "Batal",
style: "cancel",
},
{
text: "Hapus",
style: "destructive",
onPress: () => {
setItems(items.filter((item) => item.id !== id));
},
},
]);
};
return (
<View style={styles.container}>
<View style={styles.headerRow}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("TukarKoin")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>DAFTAR BARANG</Text>
</View>
<TouchableOpacity style={styles.addButton} onPress={handleAddItem}>
<Text style={styles.addButtonText}>+ Tambah Item</Text>
</TouchableOpacity>
{isEditing && (
<View style={styles.form}>
<TextInput
placeholder="Nama Barang"
value={formItem.name}
onChangeText={(text) => setFormItem({ ...formItem, name: text })}
style={styles.input}
/>
<TextInput
placeholder="Jumlah Koin"
keyboardType="numeric"
value={formItem.coin.toString()}
onChangeText={(text) => setFormItem({ ...formItem, coin: text })}
style={styles.input}
/>
{/* Tombol pilih foto */}
<TouchableOpacity style={styles.imagePickerBtn} onPress={pickImage}>
<Text style={styles.imagePickerText}>
{formItem.image ? "Ganti Foto" : "Pilih Foto"}
</Text>
</TouchableOpacity>
{/* Preview foto yang dipilih */}
{formItem.image && (
<Image source={formItem.image} style={styles.previewImage} />
)}
<TouchableOpacity style={styles.submitBtn} onPress={handleSubmit}>
<Text style={styles.submitText}>
{formItem.id ? "Simpan Perubahan" : "Tambah"}
</Text>
</TouchableOpacity>
</View>
)}
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.itemGrid}>
{items.map((item) => (
<View key={item.id} style={styles.itemCard}>
<Image source={item.image} style={styles.itemImage} />
<Text style={styles.itemName}>{item.name}</Text>
<View style={styles.coinBoxItem}>
<Text style={styles.itemCoin}>{item.coin} Koin</Text>
</View>
<View style={styles.actionRow}>
<TouchableOpacity
style={styles.editBtn}
onPress={() => handleEdit(item)}
>
<Text style={styles.actionText}>Edit</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.deleteBtn}
onPress={() => handleDelete(item.id)}
>
<Text style={styles.actionText}>Hapus</Text>
</TouchableOpacity>
</View>
</View>
))}
</View>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 20, backgroundColor: "#fff" },
backButton: { marginBottom: 10 },
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
textAlign: "left",
marginBottom: 12,
marginLeft: 20,
marginRight: 50,
},
headerRow: {
flexDirection: "row",
alignItems: "center",
marginBottom: 16,
marginTop: 30,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
},
// title: {
// fontSize: 26,
// fontWeight: "bold",
// color: "#000",
// marginBottom: 20,
// textAlign: "center",
// marginTop: 30,
// },
addButton: {
backgroundColor: "#2D572C",
paddingVertical: 12,
paddingHorizontal: 20,
borderRadius: 10,
alignSelf: "center",
marginBottom: 20,
},
addButtonText: { color: "white", fontWeight: "bold", fontSize: 16 },
form: {
backgroundColor: "#f9f9f9",
padding: 20,
borderRadius: 12,
marginBottom: 25,
borderWidth: 1,
borderColor: "#d1d1d1",
},
input: {
backgroundColor: "#fff",
padding: 14,
borderRadius: 8,
borderWidth: 1,
borderColor: "#ccc",
marginBottom: 15,
fontSize: 16,
},
imagePickerBtn: {
backgroundColor: "#DDD",
paddingVertical: 12,
borderRadius: 8,
alignItems: "center",
marginBottom: 10,
padding: 10,
width: "40%",
},
imagePickerText: {
color: "BLACK",
fontWeight: "bold",
fontSize: 16,
},
previewImage: {
width: 100,
height: 140,
alignSelf: "center",
marginBottom: 15,
resizeMode: "contain",
borderRadius: 10,
},
submitBtn: {
backgroundColor: "#2D572C",
paddingVertical: 14,
borderRadius: 8,
alignItems: "center",
},
submitText: { color: "white", fontWeight: "bold", fontSize: 16 },
itemGrid: {
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-between",
},
itemCard: {
width: "48%",
backgroundColor: "#fff",
borderRadius: 12,
padding: 15,
marginBottom: 20,
elevation: 4,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 6,
shadowOffset: { width: 0, height: 3 },
alignItems: "center",
},
itemImage: {
width: 80,
height: 110,
resizeMode: "contain",
marginBottom: 12,
},
itemName: {
fontSize: 18,
fontWeight: "bold",
color: "#2D572C",
marginBottom: 8,
textAlign: "center",
},
coinBoxItem: {
backgroundColor: "#2D572C",
paddingVertical: 6,
paddingHorizontal: 16,
borderRadius: 8,
marginBottom: 10,
},
itemCoin: {
color: "white",
fontWeight: "bold",
fontSize: 16,
},
actionRow: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
editBtn: {
flex: 1,
backgroundColor: "#4CAF50",
paddingVertical: 10,
borderRadius: 8,
alignItems: "center",
marginRight: 8,
},
deleteBtn: {
flex: 1,
backgroundColor: "#E53935",
paddingVertical: 10,
borderRadius: 8,
alignItems: "center",
},
actionText: { color: "white", fontWeight: "bold", fontSize: 14 },
});
export default DaftarBarang;

View File

@ -0,0 +1,413 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
TouchableOpacity,
ScrollView,
Linking,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const tpsData = [
{
nama: "TPS SENGKUT",
kecamatan: "BERBEK",
alamat: "Desa Werungotok, Kec. Nganjuk",
jenis: "Depo Kecil",
luas: "1,5 x 1,5",
volume: "3.375 m3",
latitude: -7.6141,
longitude: 111.5177,
},
{
nama: "TPS NGRONGGOT",
kecamatan: "BERBEK",
alamat: "Desa Werungotok, Kec. Nganjuk",
jenis: "Depo Kecil",
luas: "1,5 x 1,5",
volume: "3.375 m3",
},
{
nama: "TPS 3R MASTRIP",
kecamatan: "NGANJUK",
alamat: "Desa Mangundikaran, Kec. Nganjuk",
jenis: "TPS 3R",
luas: "2 x 2",
volume: "5 m3",
latitude: -6.6,
longitude: 106.8,
},
{
nama: "TPS 3R KARTOHARJO",
kecamatan: "NGANJUK",
alamat: "Desa Kartoharjo, Kec. Nganjuk",
jenis: "TPS 3R",
luas: "2 x 2",
volume: "5 m3",
latitude: -7.25,
longitude: 112.75,
},
{
nama: "TPS 3R KSM GANUNGKIDUL",
kecamatan: "NGANJUK",
alamat: "Desa Ganungkidul, Kec. Nganjuk",
jenis: "TPS 3R KSM",
luas: "3 x 3",
volume: "7.5 m3",
latitude: -6.175,
longitude: 106.8272,
},
{
nama: "TPS 3R KSM PAYAMAN",
kecamatan: "NGANJUK",
alamat: "Desa Payaman, Kec. Nganjuk",
jenis: "TPS 3R KSM",
luas: "3 x 3",
volume: "7.5 m3",
latitude: -6.175,
longitude: 106.8272,
},
{
nama: "TPS 3R KSM JATIREJO",
kecamatan: "NGANJUK",
alamat: "Desa Jatirejo, Kec. Nganjuk",
jenis: "TPS 3R KSM",
luas: "3 x 3",
volume: "7.5 m3",
latitude: -6.175,
longitude: 106.8272,
},
];
const DaftarTPS = () => {
const navigation = useNavigation();
const [search, setSearch] = useState("");
const [activeCategory, setActiveCategory] = useState("TPS");
const filteredTPS = tpsData.filter(
(tps) =>
tps.nama.toLowerCase().includes(search.toLowerCase()) &&
(activeCategory === "TPS" || tps.jenis === activeCategory)
);
const openInMaps = (latitude, longitude) => {
const url = `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`;
Linking.openURL(url);
};
const handleEdit = (tps) => {
console.log("Edit TPS: ", tps); // Implement the edit functionality here
// You can navigate to another screen for editing if needed
};
const handleDelete = (id) => {
console.log("Delete TPS with ID: ", id); // Implement the delete functionality here
// Handle the deletion logic, e.g., updating state or making an API call
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("Home")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>DAFTAR TPS DI NGANJUK</Text>
</View>
{/* Button for categories */}
<View style={styles.categoryButtonsContainer}>
<TouchableOpacity
style={[
styles.categoryButton,
activeCategory === "TPS" && styles.activeButton,
]}
onPress={() => setActiveCategory("TPS")}
>
<Text
style={[
styles.buttonTexts,
activeCategory === "TPS" && styles.activeButtonText,
]}
>
TPS
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.categoryButton,
activeCategory === "TPS 3R" && styles.activeButton,
]}
onPress={() => setActiveCategory("TPS 3R")}
>
<Text
style={[
styles.buttonTexts,
activeCategory === "TPS 3R" && styles.activeButtonText,
]}
>
TPS 3R
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.categoryButton,
activeCategory === "TPS 3R KSM" && styles.activeButton,
]}
onPress={() => setActiveCategory("TPS 3R KSM")}
>
<Text
style={[
styles.buttonTexts,
activeCategory === "TPS 3R KSM" && styles.activeButtonText,
]}
>
TPS 3R KSM
</Text>
</TouchableOpacity>
</View>
<View style={styles.searchContainer}>
<TextInput
placeholder="Cari Lokasi"
style={styles.input}
value={search}
onChangeText={setSearch}
/>
<TouchableOpacity style={styles.searchButton}>
<Ionicons name="search" size={20} />
</TouchableOpacity>
</View>
<ScrollView>
{filteredTPS.map((tps, index) => (
<View key={index} style={styles.card}>
<View style={styles.cardHeader}>
<View style={{ flex: 1 }}>
<Text style={styles.label}>LUAS TPS</Text>
<Text style={styles.value}>{tps.luas}</Text>
</View>
<View style={{ flex: 2 }}>
<Text style={styles.tpsName}>{tps.nama}</Text>
<Text style={styles.kecamatan}>KECAMATAN {tps.kecamatan}</Text>
</View>
<View style={{ flex: 1, alignItems: "flex-end" }}>
<Text style={styles.labelSmall}>VOLUME MAKSIMAL</Text>
<Text style={styles.volume}>{tps.volume}</Text>
</View>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Ionicons name="location-outline" size={16} />
<Text style={styles.infoText}>Alamat</Text>
<TouchableOpacity
style={styles.lokasiButton}
onPress={() => openInMaps(tps.latitude, tps.longitude)}
>
<Text style={{ fontWeight: "bold" }}>LOKASI</Text>
</TouchableOpacity>
</View>
<Text style={styles.subInfo}>{tps.alamat}</Text>
<View style={[styles.infoRow, { marginTop: 8 }]}>
<Ionicons name="trash-outline" size={16} />
<Text style={styles.infoText}>Jenis</Text>
</View>
<Text style={styles.subInfo}>{tps.jenis}</Text>
</View>
{/* Edit and Delete Buttons */}
<View style={styles.actionButtons}>
<TouchableOpacity
style={styles.editButton}
onPress={() => handleEdit(tps)} // Pass the tps object here
>
<Text style={styles.buttonText}>Edit</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.deleteButton}
onPress={() => handleDelete(tps.id)} // You can pass the id if available
>
<Text style={styles.buttonText}>Hapus</Text>
</TouchableOpacity>
</View>
</View>
))}
</ScrollView>
{/* Tambah TPS Button */}
<TouchableOpacity
style={styles.tambahButton}
onPress={() => navigation.navigate("TambahTPS")}
>
<Text style={styles.tambahButtonText}>TAMBAH TPS</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginBottom: 0,
marginTop: -40,
},
header: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
marginBottom: 10,
marginTop: 70,
},
backButton: { marginBottom: 10 },
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
textAlign: "left",
marginBottom: 12,
marginLeft: 20,
marginRight: 230,
},
categoryButtonsContainer: {
flexDirection: "row",
marginBottom: 15,
},
categoryButton: {
flex: 1,
paddingVertical: 10,
marginRight: 8,
borderRadius: 15,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#2D572C",
alignItems: "center",
justifyContent: "center",
},
activeButton: {
backgroundColor: "#2D572C",
},
buttonText: {
color: "#2D572C",
fontWeight: "bold",
},
actionButtons: {
flexDirection: "row",
justifyContent: "space-between",
padding: 10,
marginTop: 12,
},
editButton: {
backgroundColor: "#4CAF50",
paddingVertical: 8,
paddingHorizontal: 20,
borderRadius: 8,
},
deleteButton: {
backgroundColor: "#F44336",
paddingVertical: 8,
paddingHorizontal: 20,
borderRadius: 8,
},
buttonText: {
color: "#fff",
fontWeight: "bold",
},
buttonTexts: {
color: "#000",
fontWeight: "bold",
},
tambahButton: {
backgroundColor: "#f0F0F0",
paddingVertical: 12,
borderRadius: 25,
alignItems: "center",
justifyContent: "center",
marginTop: 20,
marginHorizontal: 50,
borderWidth: 0.5,
},
tambahButtonText: {
color: "#000",
fontSize: 18,
fontWeight: "bold",
},
activeButtonText: {
color: "white", // Change text color to white when the button is active
},
searchContainer: {
flexDirection: "row",
alignItems: "center",
marginBottom: 10,
},
input: {
flex: 1,
borderWidth: 1,
borderColor: "#999",
borderRadius: 10,
padding: 10,
marginBottom: 10,
},
searchButton: {
backgroundColor: "#E0E0E0",
padding: 10,
marginLeft: 8,
borderRadius: 8,
},
card: {
borderRadius: 12,
marginBottom: 20,
borderColor: "#000",
borderWidth: 1,
overflow: "hidden",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 5,
backgroundColor: "#fff",
elevation: 3,
},
cardHeader: {
backgroundColor: "#2D572C",
padding: 10,
flexDirection: "row",
alignItems: "center",
},
label: { color: "white", fontSize: 11 },
value: { color: "white", fontWeight: "bold" },
tpsName: {
color: "white",
fontSize: 16,
fontWeight: "bold",
justifyContent: "center",
marginLeft: 40,
},
kecamatan: { color: "white", fontSize: 12, marginLeft: 40 },
labelSmall: { fontSize: 10, color: "white", textAlign: "right" },
volume: { fontSize: 14, color: "white", fontWeight: "bold" },
cardContent: { padding: 12 },
infoRow: { flexDirection: "row", alignItems: "center", gap: 4 },
infoText: { fontWeight: "bold", marginLeft: 8 },
subInfo: { marginLeft: 30, fontSize: 13 },
lokasiButton: {
backgroundColor: "#F0F0F0",
paddingVertical: 8,
paddingHorizontal: 14,
borderRadius: 8,
shadowColor: "#000",
shadowOpacity: 0.1,
elevation: 2,
marginLeft: 220,
borderWidth: 1,
},
});
export default DaftarTPS;

View File

@ -0,0 +1,186 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Image } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const DetailDalamProses = () => {
const navigation = useNavigation();
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("PengaduanSampahScreenAdmin")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.headerTitle}>DALAM PROSES</Text>
</View>
{/* First Report */}
{/* Second Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar2.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Jihan Pangesti</Text>
</View>
<Text style={styles.time}>10/04/2025 13.00 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Dalam Proses</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah berserakan di Pasar Lama - JI. Sukarno, Nganjuk
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-97714168,imgsize-1547670,width-400,resizemode-4/97714168.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-87155572,imgsize-1511223,width-400,resizemode-4/87155572.jpg",
}}
style={styles.reportImage}
/>
</View>
{/* Button to contribute */}
<TouchableOpacity
style={styles.contributeButton}
onPress={() => navigation.navigate("KontribusiAdmin")}
>
<Text style={styles.contributeText}>Kontribusi Sekarang</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 0,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
marginTop: 40,
},
backButton: {
marginRight: 10,
},
headerTitle: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
reportContainer: {
marginBottom: 20,
padding: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
borderColor: "#000",
},
reportHeader: {
flexDirection: "row",
justifyContent: "space-between",
paddingBottom: 10,
},
profileContainer: {
flexDirection: "row",
alignItems: "center",
},
profileImage: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 10,
},
reporterName: {
fontSize: 16,
fontWeight: "bold",
},
time: {
fontSize: 14,
color: "#555",
},
statusButton: {
backgroundColor: "#DDD",
borderRadius: 8,
paddingVertical: 5,
paddingHorizontal: 5,
marginVertical: 8,
alignItems: "center",
width: "32%",
borderWidth: 0.5,
},
reportStatus: {
color: "#000",
fontSize: 14,
},
reportDescription: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
reportNote: {
fontSize: 14,
color: "#000",
marginBottom: 12,
},
imageContainer: {
flexDirection: "row",
justifyContent: "flex-start",
marginBottom: 12,
},
reportImage: {
width: 100,
height: 100,
borderRadius: 8,
marginRight: 5,
marginLeft: 5,
},
contributeButton: {
backgroundColor: "#2D572C",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
contributeText: {
color: "#fff",
fontSize: 16,
},
coinText: {
color: "#fff",
fontSize: 14,
},
});
export default DetailDalamProses;

View File

@ -0,0 +1,188 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Image } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const DetailDitolak = () => {
const navigation = useNavigation();
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("PengaduanSampahScreenAdmin")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.headerTitle}>DETAIL DITOLAK</Text>
</View>
{/* Report Section */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar2.png", // Ganti dengan foto profil asli
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Jihan Pangesti</Text>
</View>
<Text style={styles.time}>10/04/2025 13:00 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Ditolak</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah berserakan di Pasar Lama - JI. Sukarno, Nganjuk
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Alasan Ditolak */}
<View style={styles.alasanContainer}>
<Text style={styles.alasanTitle}>Alasan Ditolak:</Text>
<Text style={styles.alasanText}>
Pengaduan ini ditolak karena lokasi yang dilaporkan tidak sesuai
pada foto backButtonContainer yang dikirim.
</Text>
</View>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-97714168,imgsize-1547670,width-400,resizemode-4/97714168.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-87155572,imgsize-1511223,width-400,resizemode-4/87155572.jpg",
}}
style={styles.reportImage}
/>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 0,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
headerTitle: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
reportContainer: {
marginBottom: 20,
padding: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
borderColor: "#000",
},
reportHeader: {
flexDirection: "row",
justifyContent: "space-between",
paddingBottom: 10,
},
profileContainer: {
flexDirection: "row",
alignItems: "center",
},
profileImage: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 10,
},
reporterName: {
fontSize: 16,
fontWeight: "bold",
},
time: {
fontSize: 14,
color: "#555",
},
statusButton: {
backgroundColor: "#ddd",
borderRadius: 8,
paddingVertical: 5,
paddingHorizontal: 5,
marginVertical: 8,
alignItems: "center",
width: "32%",
borderWidth: 0.5,
},
reportStatus: {
color: "#000",
fontSize: 14,
},
reportDescription: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
reportNote: {
fontSize: 14,
color: "#000",
marginBottom: 12,
},
alasanContainer: {
marginTop: 20,
padding: 12,
borderRadius: 8,
backgroundColor: "#FFF3F3",
borderWidth: 1,
borderColor: "#F5B7B1",
},
alasanTitle: {
fontSize: 16,
fontWeight: "bold",
color: "#D9534F",
},
alasanText: {
fontSize: 14,
color: "#721c24",
marginTop: 8,
},
imageContainer: {
flexDirection: "row",
justifyContent: "flex-start",
marginBottom: 12,
marginTop: 12,
},
reportImage: {
width: 100,
height: 100,
borderRadius: 8,
marginRight: 5,
marginLeft: 5,
},
});
export default DetailDitolak;

View File

@ -0,0 +1,319 @@
import React, { useState } from "react";
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
Linking,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Import Ionicons untuk ikon panah
export default function DetailPengirimanAdmin({ route, navigation }) {
const { item } = route.params; // Mendapatkan data item dari navigation params
const [status, setStatus] = useState(item.status); // Menentukan status awal sesuai item
// Fungsi untuk menangani perubahan status
const handleUpdateStatus = (newStatus) => {
setStatus(newStatus); // Mengubah status pengiriman
};
// Timeline status pengiriman
const statusTimeline = {
diproses: {
title: "Diproses",
time: "23 Januari 2025, 15:12 WIB",
},
dikirim: {
title: "Dikirim",
time: "24 Januari 2025, 10:00 WIB",
},
diterima: {
title: "Diterima",
time: "25 Januari 2025, 13:00 WIB",
},
selesai: {
title: "Selesai",
time: "26 Januari 2025, 17:00 WIB",
},
};
// Fungsi untuk menghubungi penerima via WhatsApp
const handleContactRecipient = () => {
const phoneNumber = "628123456789"; // Ganti dengan nomor penerima yang terdaftar
const message = "Halo, ada update tentang pengiriman barang Anda."; // Pesan default yang ingin dikirim
const url = `whatsapp://send?phone=${phoneNumber}&text=${encodeURIComponent(
message
)}`;
// Mengecek apakah WhatsApp dapat dibuka
Linking.openURL(url).catch((err) => {
console.error("Error opening WhatsApp:", err);
});
};
const currentItem = {
...item,
statusDetails:
status === "diproses"
? "Barang sedang diproses oleh tim Dinas Lingkungan Hidup."
: status === "dikirim"
? "Barang telah dikirimkan kepada penerima."
: status === "diterima"
? "Barang telah diterima oleh penerima."
: "Pengiriman selesai.",
estimatedDate:
status === "diterima"
? "Pengiriman selesai, tidak ada tanggal estimasi lebih lanjut."
: "Diperkirakan tiba pada 30 Januari 2025.",
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>DETAIL PENGIRIMAN BARANG</Text>
</View>
{/* Hubungi Penerima Button */}
<TouchableOpacity
style={styles.contactButton}
onPress={handleContactRecipient}
>
<Text style={styles.contactText}>Hubungi Penerima</Text>
</TouchableOpacity>
{/* Image */}
<Image source={currentItem.imageUri} style={styles.image} />
{/* Product Details */}
<View style={styles.productInfo}>
<Text style={styles.productName}>{currentItem.name}</Text>
<Text style={styles.productPoints}>{currentItem.points}</Text>
</View>
{/* Foto Profil Penerima */}
<View style={styles.recipientInfo}></View>
{/* Informasi Profil Penerima */}
<View style={styles.profileInfo}>
<Text style={styles.profileText}>
Alamat: Jl. Sudirman No.5, Bandung
</Text>
<Text style={styles.profileText}>Email: siti@example.com</Text>
<Text style={styles.profileText}>No. Telepon: 082123456789</Text>
</View>
{/* Status Progress */}
<View style={styles.statusContainer}>
<Text style={styles.statusTitle}>Proses Pengiriman</Text>
<View style={styles.statusTimeline}>
{Object.keys(statusTimeline).map((step, index) => (
<View
key={index}
style={status === step ? styles.activeStep : styles.step}
>
<Text style={styles.stepText}>{statusTimeline[step].title}</Text>
<Text style={styles.time}>{statusTimeline[step].time}</Text>
</View>
))}
</View>
</View>
{/* Status Detail */}
<View style={styles.statusDetail}>
<Text style={styles.statusDetails}>{currentItem.statusDetails}</Text>
</View>
{/* Estimated Delivery */}
<View style={styles.estimatedDelivery}>
<Text style={styles.estimatedText}>{currentItem.estimatedDate}</Text>
</View>
{/* Shipping Information */}
<View style={styles.shippingInfo}>
<Text style={styles.shippingDetails}>
{currentItem.shippingAddress}
</Text>
<Text style={styles.shippingTitle}>Jasa Pengiriman</Text>
<Text style={styles.shippingDetails}>JNE</Text>
<Text style={styles.shippingTitle}>No Resi</Text>
<Text style={styles.shippingDetails}>5679032190775</Text>
</View>
{/* Buttons to update the status */}
{status === "diproses" && (
<TouchableOpacity
style={styles.button}
onPress={() => handleUpdateStatus("dikirim")}
>
<Text style={styles.buttonText}>UPDATE STATUS: DIKIRIM</Text>
</TouchableOpacity>
)}
{status === "diterima" && (
<TouchableOpacity
style={styles.button}
onPress={() => handleUpdateStatus("selesai")}
>
<Text style={styles.buttonText}>UPDATE STATUS: SELESAI</Text>
</TouchableOpacity>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: "#fff",
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 30,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
},
contactButton: {
backgroundColor: "#4CAF50",
padding: 10,
borderRadius: 5,
marginBottom: 20,
alignItems: "center",
borderRadius: 20,
marginLeft: 120,
marginRight: 120,
},
contactText: {
color: "#fff",
fontSize: 14,
},
image: {
width: 100,
height: 100,
alignSelf: "center",
marginBottom: 16,
},
productInfo: {
alignItems: "center",
marginBottom: 16,
},
productName: {
fontSize: 18,
fontWeight: "bold",
alignItems: "flex-start",
},
productPoints: {
fontSize: 14,
color: "#777",
},
recipientInfo: {
flexDirection: "row",
alignItems: "center",
marginBottom: 16,
justifyContent: "center",
},
recipientImage: {
width: 50,
height: 50,
borderRadius: 25,
marginRight: 10,
},
recipientName: {
fontSize: 16,
fontWeight: "bold",
},
profileInfo: {
marginBottom: 10,
justifyContent: "flex-start",
},
profileText: {
fontSize: 14,
color: "#777",
alignItems: "center",
alignContent: "center",
justifyContent: "center",
},
statusContainer: {
marginBottom: 16,
},
statusTitle: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 8,
},
statusTimeline: {
flexDirection: "column",
alignItems: "flex-start",
},
step: {
marginBottom: 12,
},
activeStep: {
marginBottom: 12,
borderLeftWidth: 4,
borderColor: "#4CAF50",
paddingLeft: 12,
},
stepText: {
fontSize: 14,
fontWeight: "bold",
},
time: {
fontSize: 12,
color: "#777",
},
statusDetail: {
marginBottom: 16,
},
statusDetails: {
fontSize: 14,
color: "#777",
},
estimatedDelivery: {
marginBottom: 16,
alignItems: "center",
},
estimatedText: {
fontSize: 14,
fontStyle: "italic",
},
shippingInfo: {
marginBottom: 10,
},
shippingTitle: {
fontSize: 14,
fontWeight: "bold",
},
shippingDetails: {
fontSize: 14,
marginBottom: 8,
},
button: {
marginTop: 20,
backgroundColor: "#2f4f2f",
padding: 15,
borderRadius: 10,
alignItems: "center",
},
buttonText: {
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
});

View File

@ -0,0 +1,317 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
TextInput,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native"; // Import useNavigation untuk navigasi
const DetailVerifikasi = () => {
const navigation = useNavigation();
// State untuk mengatur status tombol
const [isVerified, setIsVerified] = useState(false); // Menyimpan status verifikasi
const [showTolakForm, setShowTolakForm] = useState(false); // Menyimpan status tampilkan form alasan tolak
const [alasanTolak, setAlasanTolak] = useState(""); // Menyimpan alasan tolak pengaduan
const [isTolakClicked, setIsTolakClicked] = useState(false); // Status tombol tolak pengaduan sudah diklik
// Fungsi untuk menangani klik tombol verifikasi
const handleVerifikasi = () => {
setIsVerified(true); // Mengubah status menjadi diverifikasi
};
// Fungsi untuk mengirim alasan tolak pengaduan
const handleKirimTolak = () => {
setIsTolakClicked(true); // Mengubah status tombol tolak menjadi sudah diklik
setShowTolakForm(false); // Menutup form setelah alasan dikirim
// Navigasi ke halaman DitolakScreen dan mengirim alasan penolakan
navigation.navigate("DitolakScreen");
};
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("PengaduanSampahScreenAdmin")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.headerTitle}>VERIFIKASI</Text>
</View>
{/* First Report */}
{/* Second Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar2.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Jihan Pangesti</Text>
</View>
<Text style={styles.time}>10/04/2025 13.00 WIB</Text>
</View>
{/* Status */}
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Dalam Proses</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah berserakan di Pasar Lama - JI. Sukarno, Nganjuk
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-97714168,imgsize-1547670,width-400,resizemode-4/97714168.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-87155572,imgsize-1511223,width-400,resizemode-4/87155572.jpg",
}}
style={styles.reportImage}
/>
</View>
{/* Button to contribute (Verifikasi) */}
<TouchableOpacity
style={isVerified ? styles.verifiedButton : styles.contributeButton}
onPress={handleVerifikasi}
disabled={isVerified} // Menonaktifkan tombol jika sudah diverifikasi
>
<Text style={styles.contributeTextSudah}>
{isVerified ? "Sudah Diverifikasi" : "Verifikasi"}
</Text>
</TouchableOpacity>
{/* Button to reject the report, will hide if verified */}
{!isVerified && (
<TouchableOpacity
style={
isTolakClicked
? styles.tolakButtonDisabled
: styles.contributeButtonTolak
}
onPress={() => setShowTolakForm(true)}
disabled={isTolakClicked} // Menonaktifkan tombol jika sudah diklik
>
<Text style={styles.contributeText}>
{isTolakClicked ? "Tolak Pengaduan" : "Tolak Pengaduan"}
</Text>
</TouchableOpacity>
)}
{/* Form Alasan Tolak Pengaduan */}
{showTolakForm && (
<View style={styles.formContainer}>
<Text style={styles.formTitle}>Alasan Tolak Pengaduan</Text>
<TextInput
style={styles.textInput}
multiline
numberOfLines={4}
placeholder="Tulis alasan penolakan..."
value={alasanTolak}
onChangeText={setAlasanTolak}
/>
<TouchableOpacity
style={styles.submitButton}
onPress={handleKirimTolak}
>
<Text style={styles.submitText}>Kirim</Text>
</TouchableOpacity>
</View>
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 0,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
headerTitle: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
reportContainer: {
marginBottom: 20,
padding: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
borderColor: "#000",
},
reportHeader: {
flexDirection: "row",
justifyContent: "space-between",
paddingBottom: 10,
},
profileContainer: {
flexDirection: "row",
alignItems: "center",
},
profileImage: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 10,
},
reporterName: {
fontSize: 16,
fontWeight: "bold",
},
time: {
fontSize: 14,
color: "#555",
},
statusButton: {
backgroundColor: "#DDD",
borderRadius: 8,
paddingVertical: 5,
paddingHorizontal: 5,
marginVertical: 8,
alignItems: "center",
width: "32%",
borderWidth: 0.5,
},
reportStatus: {
color: "#000",
fontSize: 14,
},
reportDescription: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
reportNote: {
fontSize: 14,
color: "#000",
marginBottom: 12,
},
imageContainer: {
flexDirection: "row",
justifyContent: "flex-start",
marginBottom: 12,
},
reportImage: {
width: 100,
height: 100,
borderRadius: 8,
marginRight: 5,
marginLeft: 5,
},
contributeButton: {
backgroundColor: "#2D572C",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
contributeButtonTolak: {
backgroundColor: "#8b0000",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
tolakButtonDisabled: {
backgroundColor: "#A9A9A9", // Disabled gray
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
verifiedButton: {
backgroundColor: "#777b7e",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
borderWidth: 0.5,
},
contributeTextSudah: {
color: "#fff",
fontSize: 16,
},
contributeText: {
color: "#fff",
fontSize: 16,
},
formContainer: {
marginTop: 20,
},
formTitle: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 10,
},
textInput: {
height: 100,
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 8,
padding: 10,
fontSize: 16,
textAlignVertical: "top",
},
submitButton: {
backgroundColor: "#2D572C",
padding: 10,
borderRadius: 8,
marginTop: 10,
alignItems: "center",
},
submitText: {
color: "#fff",
fontSize: 16,
},
});
export default DetailVerifikasi;

View File

@ -0,0 +1,256 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
Image,
StyleSheet,
Alert,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import * as ImagePicker from "expo-image-picker"; // Mengimpor expo-image-picker
const EditProfilScreen = () => {
const navigation = useNavigation();
// State untuk data profil
const [userProfile, setUserProfile] = useState({
name: "Johan Okta Pangestu",
email: "okta@gmail.com",
phone: "08123456789",
address: "Jl. Raya No. 123, Nganjuk",
photo:
"https://i.ytimg.com/vi/b1XXKeq5ccQ/oar2.jpg?sqp=-oaymwEkCJUDENAFSFqQAgHyq4qpAxMIARUAAAAAJQAAyEI9AICiQ3gB&rs=AOn4CLBxYjkvH5GuWS8_SYMNsg5aIGYIRA", // Default photo
});
// Fungsi untuk memilih foto
const handleChoosePhoto = async () => {
// Meminta izin untuk mengakses galeri
const permissionResult =
await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.granted === false) {
alert("Izin akses galeri ditolak!");
return;
}
// Meluncurkan galeri untuk memilih gambar
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images, // Hanya gambar
quality: 0.5, // Kualitas gambar
});
if (!result.canceled) {
// Update foto profil dengan gambar yang dipilih
setUserProfile({ ...userProfile, photo: result.uri });
}
};
// Fungsi untuk menghapus foto
const handleRemovePhoto = () => {
Alert.alert(
"Konfirmasi",
"Apakah Anda yakin ingin menghapus foto profil?",
[
{ text: "Batal", style: "cancel" },
{
text: "Hapus",
onPress: () => setUserProfile({ ...userProfile, photo: "" }), // Hapus foto profil
},
]
);
};
// Fungsi untuk menyimpan perubahan profil
const handleSaveChanges = () => {
// Tampilkan alert sebagai konfirmasi
Alert.alert("Profil Diperbarui", "Perubahan profil berhasil disimpan.");
// Logika untuk menyimpan perubahan, misalnya API request, bisa ditambahkan di sini.
console.log(userProfile);
};
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.headerText}>EDIT PROFIL</Text>
</View>
{/* Foto Profil */}
<View style={styles.profileImageContainer}>
{userProfile.photo ? (
<Image
source={{ uri: userProfile.photo }}
style={styles.profileImage}
/>
) : (
<View style={styles.defaultImage}>
<Ionicons name="person-circle-outline" size={100} color="#2C6B2F" />
</View>
)}
<TouchableOpacity
style={styles.changePhotoButton}
onPress={handleChoosePhoto}
>
<Text style={styles.changePhotoButtonText}>Ubah Foto Profil</Text>
</TouchableOpacity>
{userProfile.photo && (
<TouchableOpacity
style={styles.removePhotoButton}
onPress={handleRemovePhoto}
>
<Text style={styles.removePhotoButtonText}>Hapus Foto Profil</Text>
</TouchableOpacity>
)}
</View>
{/* Form Edit Profil */}
<View style={styles.form}>
<Text style={styles.label}>Nama:</Text>
<TextInput
style={styles.input}
value={userProfile.name}
onChangeText={(text) =>
setUserProfile({ ...userProfile, name: text })
}
/>
<Text style={styles.label}>Email:</Text>
<TextInput
style={styles.input}
value={userProfile.email}
onChangeText={(text) =>
setUserProfile({ ...userProfile, email: text })
}
/>
<Text style={styles.label}>No. HP:</Text>
<TextInput
style={styles.input}
value={userProfile.phone}
onChangeText={(text) =>
setUserProfile({ ...userProfile, phone: text })
}
/>
<Text style={styles.label}>Alamat:</Text>
<TextInput
style={styles.input}
value={userProfile.address}
onChangeText={(text) =>
setUserProfile({ ...userProfile, address: text })
}
/>
</View>
{/* Tombol Simpan */}
<TouchableOpacity
style={styles.saveButton}
onPress={() => navigation.navigate("ProfilAdminScreen")}
>
<Text style={styles.saveButtonText}>Simpan</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 20,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
headerText: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
marginLeft: 10,
},
profileImageContainer: {
alignItems: "center",
marginBottom: 20,
},
profileImage: {
width: 150,
height: 150,
borderRadius: 75,
marginBottom: 10,
},
defaultImage: {
width: 150,
height: 150,
borderRadius: 75,
backgroundColor: "#ddd",
justifyContent: "center",
alignItems: "center",
},
changePhotoButton: {
backgroundColor: "#ddd",
paddingVertical: 8,
borderRadius: 8,
marginBottom: 10,
width: "30%",
alignItems: "center",
borderWidth: 0.5,
},
changePhotoButtonText: {
color: "#000",
fontWeight: "bold",
},
removePhotoButton: {
backgroundColor: "#E74C3C",
paddingVertical: 8,
borderRadius: 8,
width: "30%",
alignItems: "center",
borderWidth: 0.5,
},
removePhotoButtonText: {
color: "#fff",
fontWeight: "bold",
},
form: {
marginBottom: 20,
},
label: {
fontSize: 14,
fontWeight: "bold",
color: "#555",
marginBottom: 5,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 5,
padding: 10,
marginBottom: 20,
fontSize: 16,
color: "#333",
},
saveButton: {
backgroundColor: "#2D572C",
paddingVertical: 12,
borderRadius: 8,
alignItems: "center",
},
saveButtonText: {
fontSize: 16,
color: "#fff",
fontWeight: "bold",
},
});
export default EditProfilScreen;

View File

@ -0,0 +1,238 @@
import React, { useState, useEffect } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
TouchableOpacity,
Alert,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation, useRoute } from "@react-navigation/native";
import MapView, { Marker } from "react-native-maps";
import { Picker } from "@react-native-picker/picker";
const EditTPS = () => {
const navigation = useNavigation();
const route = useRoute();
const { tps } = route.params || {}; // Handle missing tps object gracefully
useEffect(() => {
if (tps) {
console.log("Received tps data:", tps);
} else {
console.log("No tps data received");
}
}, [tps]);
const [nama, setNama] = useState(tps?.nama || "");
const [kecamatan, setKecamatan] = useState(tps?.kecamatan || "");
const [alamat, setAlamat] = useState(tps?.alamat || "");
const [jenis, setJenis] = useState(tps?.jenis || "");
const [luas, setLuas] = useState(tps?.luas || "");
const [volume, setVolume] = useState(tps?.volume || "");
const [latitude, setLatitude] = useState(tps?.latitude?.toString() || "");
const [longitude, setLongitude] = useState(tps?.longitude?.toString() || "");
const handleSave = () => {
if (
!nama ||
!kecamatan ||
!alamat ||
!jenis ||
!luas ||
!volume ||
!latitude ||
!longitude
) {
Alert.alert("Error", "Semua field harus diisi!");
return;
}
const updatedTPS = {
...tps,
nama,
kecamatan,
alamat,
jenis,
luas,
volume,
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
};
// Here you can update your database or state with the updated data.
navigation.goBack();
Alert.alert("Sukses", "TPS berhasil diperbarui!");
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>EDIT LOKASI TPS</Text>
</View>
<ScrollView style={styles.formContainer}>
<TextInput
style={styles.input}
placeholder="Nama TPS"
value={nama}
onChangeText={setNama}
/>
<TextInput
style={styles.input}
placeholder="Luas TPS (m2)"
value={luas}
keyboardType="numeric"
onChangeText={setLuas}
/>
<TextInput
style={styles.input}
placeholder="Volume (m³)"
value={volume}
keyboardType="numeric"
onChangeText={setVolume}
/>
<Text style={styles.label}>Pilih Jenis TPS</Text>
<Picker
selectedValue={jenis}
style={styles.picker}
onValueChange={(itemValue) => setJenis(itemValue)}
>
<Picker.Item label="Container" value="Container" />
<Picker.Item label="Depo Kecil" value="Depo Kecil" />
</Picker>
<TextInput
style={styles.input}
placeholder="Alamat"
value={alamat}
onChangeText={setAlamat}
/>
<Text style={styles.label}>Pilih Kecamatan</Text>
<Picker
selectedValue={kecamatan}
style={styles.picker}
onValueChange={(itemValue) => setKecamatan(itemValue)}
>
<Picker.Item label="Nganjuk" value="Nganjuk" />
<Picker.Item label="Bagor" value="Bagor" />
<Picker.Item label="Wilangan" value="Wilangan" />
<Picker.Item label="Baron" value="Baron" />
</Picker>
<TextInput
style={styles.input}
placeholder="Latitude"
value={latitude}
keyboardType="numeric"
onChangeText={setLatitude}
/>
<TextInput
style={styles.input}
placeholder="Longitude"
value={longitude}
keyboardType="numeric"
onChangeText={setLongitude}
/>
{/* MapView to show location */}
{latitude && longitude ? (
<MapView
style={styles.map}
initialRegion={{
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
}}
/>
</MapView>
) : null}
<TouchableOpacity style={styles.saveButton} onPress={handleSave}>
<Text style={styles.saveButtonText}>SIMPAN</Text>
</TouchableOpacity>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 30,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 20,
},
title: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
formContainer: {
marginTop: -15,
padding: 15,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 15,
marginBottom: 12,
fontSize: 14,
},
label: {
fontSize: 14,
fontWeight: "bold",
marginBottom: 5,
},
picker: {
height: 50,
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
marginBottom: 12,
},
map: {
height: 200,
marginBottom: 20,
},
saveButton: {
width: "100%",
padding: 15,
backgroundColor: "#2D572C",
alignItems: "center",
borderRadius: 15,
},
saveButtonText: {
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
});
export default EditTPS;

View File

@ -0,0 +1,88 @@
// ExpensePage.js
import React from 'react';
import { View, Text, StyleSheet, ScrollView } from 'react-native';
const ExpensePage = () => {
// Data pengeluaran untuk pengelolaan sampah, bisa diganti dengan data dari API atau state global
const expenses = [
{ id: 1, description: 'Biaya Transportasi Pengangkutan Sampah', amount: 3000000 },
{ id: 2, description: 'Biaya Pemeliharaan TPS', amount: 1200000 },
{ id: 3, description: 'Gaji Petugas Pengelola Sampah', amount: 1500000 },
{ id: 4, description: 'Biaya Pengadaan Alat Pengelolaan Sampah', amount: 800000 },
{ id: 5, description: 'Biaya Sosialisasi Pengelolaan Sampah', amount: 500000 },
];
const totalExpense = expenses.reduce((total, expense) => total + expense.amount, 0);
return (
<ScrollView style={styles.container}>
<Text style={styles.header}>Halaman Pengeluaran Pengelolaan Sampah</Text>
<View style={styles.expensesList}>
{expenses.map((expense) => (
<View key={expense.id} style={styles.expenseItem}>
<Text style={styles.description}>{expense.description}</Text>
<Text style={styles.amount}>Rp {expense.amount.toLocaleString()}</Text>
</View>
))}
</View>
<View style={styles.totalContainer}>
<Text style={styles.totalText}>Total Pengeluaran Pengelolaan Sampah:</Text>
<Text style={styles.totalAmount}>Rp {totalExpense.toLocaleString()}</Text>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
backgroundColor: '#f8f8f8',
},
header: {
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
marginBottom: 20,
},
expensesList: {
marginBottom: 20,
},
expenseItem: {
backgroundColor: '#fff',
padding: 15,
marginBottom: 10,
borderRadius: 5,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 5,
},
description: {
fontSize: 16,
fontWeight: '600',
},
amount: {
fontSize: 16,
color: '#888',
},
totalContainer: {
backgroundColor: '#fff',
padding: 15,
borderRadius: 5,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 5,
},
totalText: {
fontSize: 18,
fontWeight: 'bold',
},
totalAmount: {
fontSize: 18,
color: '#f00',
marginTop: 10,
},
});
export default ExpensePage;

View File

@ -0,0 +1,195 @@
import React, { useState } from "react";
import {
ScrollView,
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Icon library for the media buttons
const KontribusiAdmin = ({ navigation, route }) => {
// Destructuring safely with fallback values if route.params is undefined
const {
judulPengaduan = "Sampah berantakan",
tempatPengaduan = "Jl Raya Madiun Nganjuk",
} = route?.params || {};
const [catatan, setCatatan] = useState("");
return (
<ScrollView style={styles.container}>
{/* Title and Back Button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>KONTRIBUSI SEKARANG</Text>
</View>
{/* Contribution Info Container */}
<View style={styles.contributionContainer}>
<View style={styles.infoBox}>
<Text style={styles.infoText1}>{judulPengaduan}</Text>
<Text style={styles.infoText2}>{tempatPengaduan}</Text>
</View>
{/* Add Media Row (Foto & Video) */}
<View style={styles.mediaRow}>
<TouchableOpacity style={styles.mediaButton}>
<Ionicons name="image-outline" size={30} color="#2D572C" />
<Text style={styles.mediaButtonText}>Tambah Foto</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.mediaButton}>
<Ionicons name="videocam-outline" size={30} color="#2D572C" />
<Text style={styles.mediaButtonText}>Tambah Video</Text>
</TouchableOpacity>
</View>
{/* Catatan (Note Input) */}
<TextInput
style={styles.input}
placeholder="Catatan"
multiline
value={catatan}
onChangeText={setCatatan}
/>
</View>
{/* Koin Message */}
<Text style={styles.koinText}>Dapatkan +520 Koin</Text>
{/* Post Button at Bottom */}
<TouchableOpacity
style={styles.postButton}
onPress={() => navigation.navigate("KontribusiBerhasilAdmin")}
>
<Text style={styles.postButtonText}>Posting</Text>
</TouchableOpacity>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
// marginTop: 30,
backgroundColor: "#f9f9f9",
},
header: {
marginTop: 40,
flexDirection: "row", // Aligns items horizontally
alignItems: "center", // Vertically centers items
padding: 15,
backgroundColor: "#fff", // Dark green background
borderBottomLeftRadius: 20,
borderBottomRightRadius: 20,
},
backButton: {
marginRight: 15, // Adds spacing between the back button and the title
},
title: {
fontSize: 22,
color: "#000",
fontWeight: "bold",
flex: 1, // Ensures title takes up remaining space
textAlign: "left",
},
contributionContainer: {
padding: 20,
backgroundColor: "#fff",
marginBottom: 20,
borderRadius: 12,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 4 },
shadowRadius: 4,
// elevation: 5, // For Android shadow
},
infoBox: {
marginBottom: 20,
},
infoText1: {
fontSize: 22,
color: "#333",
fontWeight: "700",
marginBottom: 5,
},
infoText2: {
fontSize: 18,
color: "#777",
fontWeight: "400",
},
mediaRow: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 25,
},
mediaButton: {
alignItems: "center",
flex: 1,
padding: 15,
backgroundColor: "#E8F5E9", // Light green background
borderRadius: 10,
marginHorizontal: 10,
borderWidth: 1,
borderColor: "#2D572C",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 3 },
shadowRadius: 5,
elevation: 3,
},
mediaButtonText: {
fontSize: 14,
color: "#2D572C",
marginTop: 5,
},
input: {
height: 100,
borderColor: "#2D572C",
borderWidth: 1,
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 15,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 5,
elevation: 2,
},
koinText: {
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
color: "#2D572C",
marginBottom: 20,
},
postButton: {
backgroundColor: "#2D572C", // Dark Green
paddingVertical: 15,
borderRadius: 10,
marginBottom: 20,
alignItems: "center",
width: "90%",
alignSelf: "center",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 5 },
shadowRadius: 8,
elevation: 5,
},
postButtonText: {
fontSize: 18,
color: "#fff",
fontWeight: "bold",
},
});
export default KontribusiAdmin;

View File

@ -0,0 +1,80 @@
import React from "react";
import { View, Text, Button, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons"; // Menggunakan ikon ceklis
const KontribusiBerhasilAdmin = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={styles.content}>
<MaterialCommunityIcons name="cloud-check" size={140} color="white" />
<Text style={styles.title}>Kontribusi Berhasil !</Text>
{/* <Text style={styles.message}>
Mohon pastikan informasi yang diberikan sudah sesuai, agar kami dapat
segera menindaklanjuti.
</Text> */}
<Text style={styles.subMessage}>
Terima kasih telah berkontribusi untuk lingkungan!
</Text>
<TouchableOpacity
style={styles.button}
// onPress={() => console.log("Daftar Submit")}
onPress={() => navigation.navigate("BerandaPengaduanAdmin")}
>
<Text style={styles.buttonText}>LIHAT KONTRIBUSI</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap
},
content: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk efek overlay
padding: 30,
borderRadius: 15,
width: "80%",
alignItems: "center",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#ffea00",
marginTop: 0,
},
message: {
fontSize: 16,
color: "#fff",
textAlign: "center",
marginTop: 10,
},
subMessage: {
fontSize: 15,
color: "#ffea00",
textAlign: "center",
marginTop: 10,
padding: 3,
},
button: {
backgroundColor: "#fff",
paddingVertical: 10,
paddingHorizontal: 40,
borderRadius: 5,
marginTop: 20,
borderRadius: 25,
fontWeight: "bold",
},
buttonText: {
fontWeight: "bold",
fontSize: 15,
},
});
export default KontribusiBerhasilAdmin;

View File

@ -0,0 +1,347 @@
import React, { useState } from "react";
import { Ionicons, MaterialIcons } from "@expo/vector-icons"; // I
import {
View,
Text,
StyleSheet,
Button,
Modal,
TouchableOpacity,
FlatList,
} from "react-native";
import * as Print from "expo-print";
import * as FileSystem from "expo-file-system";
import { useNavigation } from "@react-navigation/native"; // Import useNavigation untuk navigasi
const Laporan = () => {
const navigation = useNavigation();
const [bulan, setBulan] = useState("Januari");
const [modalVisible, setModalVisible] = useState(false);
const [selectedReport, setSelectedReport] = useState(null);
const data = {
tpsData: [
{ tps: "TPS 1", jumlah: 150 },
{ tps: "TPS 2", jumlah: 200 },
{ tps: "TPS 3", jumlah: 180 },
],
pengaduanData: [
{ bulan: "Januari", jumlah: 25 },
{ bulan: "Februari", jumlah: 30 },
{ bulan: "Maret", jumlah: 18 },
],
penukaranKoinData: [
{ bulan: "Januari", jumlah: 1500 },
{ bulan: "Februari", jumlah: 2000 },
{ bulan: "Maret", jumlah: 1200 },
],
donasiData: [
{ bulan: "Januari", jumlah: 100000 },
{ bulan: "Februari", jumlah: 120000 },
{ bulan: "Maret", jumlah: 80000 },
],
};
const filterDataByMonth = (month) => {
const filteredData = {
tpsData: data.tpsData,
pengaduanData: data.pengaduanData.filter((item) => item.bulan === month),
penukaranKoinData: data.penukaranKoinData.filter(
(item) => item.bulan === month
),
donasiData: data.donasiData.filter((item) => item.bulan === month),
};
return filteredData;
};
const generatePDF = async (reportType) => {
const filteredData = filterDataByMonth(bulan);
let htmlContent = "";
if (reportType === "tps") {
htmlContent = `
<h1 style="text-align:center;">Laporan TPS di Nganjuk</h1>
<table border="1" style="width:100%; text-align:left;">
<tr>
<th>TPS</th>
<th>Jumlah</th>
</tr>
${filteredData.tpsData
.map(
(item) => `
<tr>
<td>${item.tps}</td>
<td>${item.jumlah}</td>
</tr>`
)
.join("")}
</table>
`;
} else if (reportType === "pengaduan") {
htmlContent = `
<h1 style="text-align:center;">Laporan Pengaduan Sampah - ${bulan}</h1>
<table border="1" style="width:100%; text-align:left;">
<tr>
<th>Bulan</th>
<th>Jumlah Pengaduan</th>
</tr>
${filteredData.pengaduanData
.map(
(item) => `
<tr>
<td>${item.bulan}</td>
<td>${item.jumlah}</td>
</tr>`
)
.join("")}
</table>
`;
} else if (reportType === "penukaran") {
htmlContent = `
<h1 style="text-align:center;">Laporan Penukaran Koin - ${bulan}</h1>
<table border="1" style="width:100%; text-align:left;">
<tr>
<th>Bulan</th>
<th>Jumlah Koin</th>
</tr>
${filteredData.penukaranKoinData
.map(
(item) => `
<tr>
<td>${item.bulan}</td>
<td>${item.jumlah}</td>
</tr>`
)
.join("")}
</table>
`;
} else if (reportType === "donasi") {
htmlContent = `
<h1 style="text-align:center;">Laporan Donasi - ${bulan}</h1>
<table border="1" style="width:100%; text-align:left;">
<tr>
<th>Bulan</th>
<th>Jumlah Donasi</th>
</tr>
${filteredData.donasiData
.map(
(item) => `
<tr>
<td>${item.bulan}</td>
<td>Rp ${item.jumlah.toLocaleString()}</td>
</tr>`
)
.join("")}
</table>
`;
}
try {
const { uri } = await Print.printToFileAsync({ html: htmlContent });
console.log("PDF berhasil dibuat di:", uri);
alert(`PDF berhasil dibuat! File disimpan di: ${uri}`);
} catch (error) {
console.error("Error saat membuat PDF:", error);
alert("Gagal membuat PDF.");
}
};
const months = [
"Januari",
"Februari",
"Maret",
"April",
"Mei",
"Juni",
"Juli",
"Agustus",
"September",
"Oktober",
"November",
"Desember",
];
return (
<View style={styles.container}>
{/* <Text style={styles.headerTitle}>Laporan Data</Text> */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("AdminScreen")}
>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>LAPORAN</Text>
</View>
{/* Tombol untuk Memilih Laporan */}
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.reportButton}
onPress={() => {
setSelectedReport("tps");
setModalVisible(true);
}}
>
<Text style={styles.buttonText}>TPS di Nganjuk</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.reportButton}
onPress={() => {
setSelectedReport("pengaduan");
setModalVisible(true);
}}
>
<Text style={styles.buttonText}>Pengaduan Sampah</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.reportButton}
onPress={() => {
setSelectedReport("penukaran");
setModalVisible(true);
}}
>
<Text style={styles.buttonText}>Penukaran Koin</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.reportButton}
onPress={() => {
setSelectedReport("donasi");
setModalVisible(true);
}}
>
<Text style={styles.buttonText}>Donasi</Text>
</TouchableOpacity>
</View>
{/* Modal untuk memilih bulan */}
<Modal
visible={modalVisible}
transparent={true}
animationType="slide"
onRequestClose={() => setModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Pilih Bulan</Text>
<FlatList
data={months}
numColumns={3}
keyExtractor={(item) => item}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.monthButton}
onPress={() => {
setBulan(item);
generatePDF(selectedReport);
setModalVisible(false);
}}
>
<Text style={styles.monthButtonText}>{item}</Text>
</TouchableOpacity>
)}
/>
<TouchableOpacity
style={styles.closeButton}
onPress={() => setModalVisible(false)}
>
<Text style={styles.closeButtonText}>Tutup</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 12,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
},
headerTitle: {
fontSize: 22,
fontWeight: "bold",
marginBottom: 20,
textAlign: "center",
},
buttonContainer: {
marginBottom: 20,
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-around",
},
reportButton: {
backgroundColor: "#2D572C",
padding: 20,
borderRadius: 8,
marginBottom: 10,
width: "100%",
alignItems: "center",
},
buttonText: {
color: "#fff",
fontSize: 20,
textAlign: "center",
},
modalContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.5)",
},
modalContent: {
backgroundColor: "#fff",
padding: 20,
borderRadius: 10,
width: 300,
},
modalTitle: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 10,
textAlign: "center",
},
monthButton: {
backgroundColor: "#4CAF50",
margin: 5,
padding: 10,
borderRadius: 5,
flex: 1,
justifyContent: "center",
alignItems: "center",
},
monthButtonText: {
color: "#fff",
fontSize: 14,
},
closeButton: {
backgroundColor: "#ddd",
padding: 10,
borderRadius: 5,
marginTop: 20,
alignItems: "center",
borderWidth: 1,
},
closeButtonText: {
color: "#000",
fontSize: 16,
},
});
export default Laporan;

View File

@ -0,0 +1,155 @@
import React from "react";
import { View, Text, StyleSheet, ScrollView } from "react-native";
import { Ionicons, MaterialIcons } from "@expo/vector-icons"; // Importing icons
import { useNavigation } from "@react-navigation/native";
import BottomTabAdmin from "../../Navigation/BottomTabAdmin";
const NotifikasiAdminScreen = () => {
const navigation = useNavigation();
// Get current date and time
const currentDate = new Date();
const formattedDate = `${currentDate.toLocaleDateString()} ${currentDate.toLocaleTimeString()}`;
return (
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{/* Header */}
<View>
<Text style={styles.title}>NOTIFIKASI ADMIN</Text>
</View>
{/* Notification 1: New User Report */}
<View style={styles.notification}>
<MaterialIcons name="report-problem" size={24} color="#e74c3c" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>Laporan pengguna baru!</Text>
<Text style={styles.notificationDescription}>
Pengguna baru melaporkan masalah terkait sistem. Harap tinjau
segera.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 2: Task Assigned to You */}
<View style={styles.notification}>
<Ionicons name="clipboard" size={24} color="#3498db" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
Tugas baru telah ditugaskan!
</Text>
<Text style={styles.notificationDescription}>
Anda telah ditugaskan untuk meninjau laporan terbaru yang masuk.
Silakan cek sekarang.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 3: System Maintenance Update */}
<View style={styles.notification}>
<Ionicons name="construct" size={24} color="#f39c12" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
Pembaruan sistem sedang berjalan.
</Text>
<Text style={styles.notificationDescription}>
Pembaruan sistem akan memengaruhi akses beberapa fitur. Harap
bersabar.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 4: New Trash Pickup Location */}
<View style={styles.notification}>
<Ionicons name="location-sharp" size={24} color="#27ae60" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
TPS baru telah ditambahkan!
</Text>
<Text style={styles.notificationDescription}>
Lokasi pembuangan sampah terbaru sudah tersedia di sistem. Cek
peta untuk detailnya.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
</ScrollView>
{/* Bottom Navigation */}
<View style={styles.bottomNavigationContainer}>
<BottomTabAdmin />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // Flex untuk menutupi seluruh layar
backgroundColor: "#f9f9f9",
paddingHorizontal: 20,
paddingTop: 10,
},
scrollContainer: {
flex: 1, // Agar ScrollView mengisi ruang yang tersisa
paddingBottom: 80, // Menambahkan ruang untuk bottom navigation
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
marginLeft: 10,
marginBottom: 20,
marginTop: 40,
},
notification: {
flexDirection: "row",
alignItems: "center",
backgroundColor: "#fff",
padding: 15,
marginBottom: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: "#ddd",
},
notificationText: {
marginLeft: 15,
flex: 1,
},
notificationTitle: {
fontSize: 16,
fontWeight: "bold",
color: "#333",
},
notificationDescription: {
fontSize: 14,
color: "#555",
},
notificationDate: {
fontSize: 12,
color: "#888", // Lighter color for date
marginTop: 5,
},
bottomNavigationContainer: {
position: "absolute",
bottom: 0,
left: 0, // Memberikan ruang kiri sedikit
right: 0, // Memberikan ruang kanan sedikit
height: 60,
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
});
export default NotifikasiAdminScreen;

View File

@ -0,0 +1,231 @@
import React, { useState } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
ScrollView,
} from "react-native";
import { Ionicons, MaterialIcons } from "@expo/vector-icons"; // Importing icons
import { useNavigation } from "@react-navigation/native";
const PengaduanSampahScreenAdmin = () => {
const [filter, setFilter] = useState("all"); // State to manage the active filter
const navigation = useNavigation();
// Function to navigate to the details page
const goToDetailPage = (status) => {
navigation.navigate(`Detail${status}`);
};
// Sample data for reports
const reports = [
{
title: "Sampah Berantakan",
location: "Pasar Nganjuk - Jl. Sukomoro Nganjuk",
status: "Selesai",
date: "10 April 2025 - 14:30",
},
{
title: "Sampah Pinggir Jalan",
location: "Pasar Madiun - Jl. Raya Madiun",
status: "Dalam Proses",
date: "10 April 2025 - 13:00",
},
{
title: "TPS Liar",
location: "Pasar Kediri - Jl. Raya Kediri",
status: "Verifikasi",
date: "9 April 2025 - 15:20",
},
{
title: "Sampah Depan SMA 1",
location: "Pasar Surabaya - Jl. Raya Surabaya",
status: "Ditolak",
date: "8 April 2025 - 10:45",
},
];
// Filter reports based on the active filter
const filteredReports = reports.filter(
(report) => filter === "all" || report.status === filter
);
return (
<ScrollView style={styles.container}>
{/* Header with Title and Back Button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("AdminScreen")}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>PENGADUAN SAMPAH</Text>
</View>
{/* Filter Buttons */}
<View style={styles.filterContainer}>
<TouchableOpacity
style={[styles.filterButton, filter === "all" && styles.activeFilter]}
onPress={() => setFilter("all")}
>
<Text style={styles.filterButtonText}>Semua</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.filterButton,
filter === "Verifikasi" && styles.activeFilter,
]}
onPress={() => setFilter("Verifikasi")}
>
<Text style={styles.filterButtonText}>Verifikasi</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.filterButton,
filter === "Dalam Proses" && styles.activeFilter,
]}
onPress={() => setFilter("Dalam Proses")}
>
<Text style={styles.filterButtonText}>Dalam Proses</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.filterButton,
filter === "Selesai" && styles.activeFilter,
]}
onPress={() => setFilter("Selesai")}
>
<Text style={styles.filterButtonText}>Selesai</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.filterButton,
filter === "Ditolak" && styles.activeFilter,
]}
onPress={() => setFilter("Ditolak")}
>
<Text style={styles.filterButtonText}>Ditolak</Text>
</TouchableOpacity>
</View>
{/* Report Content */}
{filteredReports.map((report, index) => (
<View style={styles.reportContainer} key={index}>
<Text style={styles.reportTitle}>{report.title}</Text>
<Text style={styles.reportLocation}>{report.location}</Text>
<View style={styles.statusContainer}>
<TouchableOpacity
style={[
styles.statusBox,
report.status === "Selesai" && styles.statusDone,
report.status === "Dalam Proses" && styles.statusInProgress,
report.status === "Verifikasi" && styles.statusOnProcess,
report.status === "Ditolak" && styles.statusRejected,
]}
onPress={() => goToDetailPage(report.status)}
>
<Text style={styles.statusText}>{report.status}</Text>
</TouchableOpacity>
<Text style={styles.dateTimeText}>{report.date}</Text>
</View>
</View>
))}
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f9f9f9",
padding: 20,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 20,
fontWeight: "bold",
color: "#333",
},
filterContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 20,
},
filterButton: {
paddingVertical: 8,
paddingHorizontal: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
},
filterButtonText: {
fontSize: 14,
color: "#333",
},
activeFilter: {
backgroundColor: "#dcdcdc", // Green color for active filter
},
reportContainer: {
backgroundColor: "#fff",
padding: 15,
marginBottom: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: "#ddd",
},
reportTitle: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
reportLocation: {
fontSize: 14,
color: "#555",
marginBottom: 10,
},
statusContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
statusBox: {
paddingVertical: 8,
paddingHorizontal: 12,
borderRadius: 8,
justifyContent: "center",
alignItems: "center",
},
statusDone: {
backgroundColor: "#d1f0d1", // Light Green
},
statusInProgress: {
backgroundColor: "#d1e3f0", // Light Blue
},
statusOnProcess: {
backgroundColor: "#f0e0a1", // Light Yellow
},
statusRejected: {
backgroundColor: "#f0c1c1", // Light Red
},
statusText: {
fontSize: 14,
color: "#333",
},
dateTimeText: {
fontSize: 12,
color: "#555",
},
});
export default PengaduanSampahScreenAdmin;

View File

@ -0,0 +1,159 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
ScrollView,
Alert,
ToastAndroid,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const PosterEdukasiScreen = () => {
const navigation = useNavigation();
// State untuk menyimpan daftar poster
const [posters, setPosters] = useState([
{ id: 1, image: require("../../assets/images/poster1.png") },
{ id: 2, image: require("../../assets/images/poster2.png") }, // Tambah poster kedua
{ id: 2, image: require("../../assets/images/poster3.png") }, // Tambah poster kedua
// Tambahkan poster lainnya sesuai kebutuhan
]);
// Handle add poster action
const handleAddPoster = () => {
navigation.navigate("AddPosterScreen");
};
// Fungsi untuk menghapus poster
const handleDeletePoster = (posterId) => {
Alert.alert(
"Hapus Poster",
"Apakah Anda yakin ingin menghapus poster ini?",
[
{
text: "Batal",
style: "cancel",
},
{
text: "Hapus",
onPress: () => {
// Hapus poster berdasarkan ID
const updatedPosters = posters.filter(
(poster) => poster.id !== posterId
);
setPosters(updatedPosters);
ToastAndroid.show("Poster telah dihapus", ToastAndroid.SHORT);
},
},
]
);
};
return (
<ScrollView style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>POSTER EDUKASI</Text>
</View>
{/* Daftar Poster */}
<View style={styles.posterList}>
{posters.map((poster) => (
<View key={poster.id} style={styles.posterItem}>
<TouchableOpacity onPress={() => handleDeletePoster(poster.id)}>
<Image source={poster.image} style={styles.posterImage} />
{/* Tombol Hapus Poster */}
<TouchableOpacity
style={styles.deleteIcon}
onPress={() => handleDeletePoster(poster.id)}
>
<Ionicons name="trash" size={24} color="white" />
</TouchableOpacity>
</TouchableOpacity>
</View>
))}
</View>
{/* Add Poster Button */}
<View style={styles.addPosterContainer}>
<TouchableOpacity style={styles.addButton} onPress={handleAddPoster}>
<Ionicons name="add-circle" size={24} color="#FFF" />
<Text style={styles.addButtonText}>Tambah Poster</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFF",
padding: 16,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 12,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
},
posterList: {
marginBottom: 20,
},
posterItem: {
position: "relative",
marginBottom: 15,
},
posterImage: {
width: "100%",
height: 250,
resizeMode: "contain",
borderRadius: 8,
},
deleteIcon: {
position: "absolute",
top: 10,
right: 10,
backgroundColor: "red",
padding: 6,
borderRadius: 16,
},
addPosterContainer: {
marginTop: 20,
alignItems: "center",
marginBottom: 50,
},
addButton: {
backgroundColor: "#2D572C",
paddingVertical: 12,
paddingHorizontal: 32,
borderRadius: 8,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
addButtonText: {
color: "#FFF",
fontWeight: "bold",
marginLeft: 8,
},
});
export default PosterEdukasiScreen;

View File

@ -0,0 +1,265 @@
import React from "react";
import {
View,
Text,
Image,
TouchableOpacity,
StyleSheet,
Alert,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import BottomTabAdmin from "../../Navigation/BottomTabAdmin";
const ProfilAdminScreen = () => {
const navigation = useNavigation();
const userProfile = {
name: "Johan Okta Pangestu",
email: "okta@gmail.com",
phone: "08123456789",
address: "Jl. Raya No. 123, Nganjuk",
joinDate: "January 15, 2023",
};
const handleLogout = () => {
Alert.alert(
"Konfirmasi Keluar",
"Apakah Anda yakin ingin keluar dari aplikasi?",
[
{
text: "Tidak",
onPress: () => console.log("Logout cancelled"),
style: "cancel",
},
{
text: "Yakin",
onPress: () => {
console.log("User logged out");
navigation.navigate("AksesAkun"); // Navigasi ke halaman masuk admin
},
},
],
{ cancelable: false }
);
};
return (
<View style={styles.container}>
{/* Profile Section */}
<View style={styles.profileSection}>
<Image
source={{
uri: "https://i.ytimg.com/vi/b1XXKeq5ccQ/oar2.jpg?sqp=-oaymwEkCJUDENAFSFqQAgHyq4qpAxMIARUAAAAAJQAAyEI9AICiQ3gB&rs=AOn4CLBxYjkvH5GuWS8_SYMNsg5aIGYIRA",
}}
style={styles.profileImage}
/>
<View style={styles.profileTextContainer}>
<TouchableOpacity
style={styles.editButton}
onPress={() => navigation.navigate("EditProfilScreen")}
>
<Text style={styles.editButtonText}>Edit Profil</Text>
</TouchableOpacity>
<Text style={styles.greetingText}>Hi, {userProfile.name}</Text>
<Text style={styles.envMessageText}>
Keberihan lingkungan sekitar anda wajib terjaga
</Text>
<View style={styles.dinasBox}>
<Text style={styles.dinasText}>DINAS LINGKUNGAN HIDUP</Text>
</View>
</View>
</View>
{/* Profile Information Section */}
<View style={styles.infoSection}>
<Text style={styles.infoLabel}>Nama:</Text>
<Text style={styles.infoText}>{userProfile.name}</Text>
<Text style={styles.infoLabel}>Email:</Text>
<Text style={styles.infoText}>{userProfile.email}</Text>
<Text style={styles.infoLabel}>No. HP:</Text>
<Text style={styles.infoText}>{userProfile.phone}</Text>
<Text style={styles.infoLabel}>Alamat:</Text>
<Text style={styles.infoText}>{userProfile.address}</Text>
<Text style={styles.infoLabel}>Tanggal Bergabung:</Text>
<Text style={styles.infoText}>{userProfile.joinDate}</Text>
</View>
{/* Logout Button */}
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Text style={styles.logoutButtonText}>KELUAR AKUN</Text>
</TouchableOpacity>
{/* Bottom Navigation */}
<View style={styles.bottomNav}>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("AksesAkun")}
>
<Ionicons name="home" size={30} color="#2C6B2F" />
<Text style={styles.navText}>UTAMA</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("NotifikasiAdminScreen")}
>
<View style={styles.notifIconContainer}>
<Ionicons name="notifications-outline" size={24} color="#2C6B2F" />
<View style={styles.badge}>
<Text style={styles.badgeText}>1</Text>
</View>
</View>
<Text style={styles.navText}>NOTIFIKASI</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("ProfilAdminScreen")}
>
<Ionicons name="person-circle-outline" size={24} color="#2C6B2F" />
<Text style={styles.navText}>PROFIL</Text>
</TouchableOpacity>
</View>
<BottomTabAdmin />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
profileSection: {
alignItems: "center",
padding: 20,
backgroundColor: "#fff",
borderBottomWidth: 1,
borderBottomColor: "#ddd",
marginTop: 30,
},
profileImage: {
width: 150,
height: 150,
borderRadius: 75,
marginBottom: 20,
},
profileTextContainer: {
alignItems: "center",
justifyContent: "center",
},
greetingText: {
fontSize: 30,
fontWeight: "bold",
color: "#333",
},
envMessageText: {
fontSize: 14,
color: "#555",
marginVertical: 5,
},
dinasBox: {
backgroundColor: "#ddd",
paddingVertical: 3,
paddingHorizontal: 12,
marginTop: 1,
borderRadius: 8,
borderColor: "#000",
alignItems: "center",
borderWidth: 0.5,
},
dinasText: {
fontSize: 12,
fontWeight: "bold",
color: "#333",
},
editButton: {
backgroundColor: "#fff",
paddingVertical: 5,
borderRadius: 8,
alignItems: "center",
marginTop: 10,
paddingHorizontal: 30,
marginBottom: 5,
borderWidth: 1,
borderColor: "#000",
},
editButtonText: {
fontSize: 16,
color: "#000",
fontWeight: "bold",
},
infoSection: {
paddingHorizontal: 20,
marginBottom: 20,
},
infoLabel: {
fontSize: 14,
fontWeight: "bold",
color: "#555",
marginTop: 10,
},
infoText: {
fontSize: 16,
color: "#777",
marginBottom: 15,
},
logoutButton: {
backgroundColor: "#fff",
paddingVertical: 12,
borderRadius: 8,
alignItems: "center",
marginHorizontal: 20,
marginBottom: 20,
borderWidth: 0.5,
elevation: 1,
},
logoutButtonText: {
fontSize: 16,
color: "#000",
fontWeight: "bold",
},
bottomNav: {
position: "absolute",
bottom: 0,
width: "100%",
flexDirection: "row",
justifyContent: "space-evenly",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
navItem: {
alignItems: "center",
padding: 6,
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 5,
marginHorizontal: 5,
},
navText: { color: "#2C6B2F", fontSize: 12, marginTop: 5 },
notifIconContainer: { position: "relative" },
badge: {
position: "absolute",
right: -5,
top: -5,
backgroundColor: "#E74C3C",
borderRadius: 10,
paddingHorizontal: 6,
paddingVertical: 2,
},
badgeText: { color: "#fff", fontSize: 10, fontWeight: "bold" },
});
export default ProfilAdminScreen;

View File

@ -0,0 +1,158 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
ScrollView,
StyleSheet,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Import Ionicons for back icon
import { useNavigation } from "@react-navigation/native";
// Sample data for donation history
const donations = [
{
id: 1,
name: "John Doe",
tujuan: "Edukasi Lingkungan",
catatan: "-",
tanggal: "2025-05-19",
waktu: "14:30",
nominal: "Rp 500.000",
},
{
id: 2,
name: "Jane Smith",
tujuan: "Pengelolaan Sampah",
catatan: "Donasi untuk pengadaan tempat sampah",
tanggal: "2025-06-01",
waktu: "10:00",
nominal: "Rp 150.000",
},
{
id: 3,
name: "Mark Wilson",
tujuan: "Program Pelatihan",
catatan: "Untuk program pelatihan masyarakat",
tanggal: "2025-04-15",
waktu: "16:45",
nominal: "Rp 300.000",
},
];
export default function RiwayatDonasiAdmin() {
const navigation = useNavigation();
return (
<ScrollView contentContainerStyle={styles.container}>
{/* Back Button */}
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()} // Go back to previous screen
>
<Ionicons name="arrow-back" size={30} color="#000" />
</TouchableOpacity>
{/* Title */}
<Text style={styles.title}>RIWAYAT DONASI</Text>
{/* Donation History List */}
<View style={styles.historyBox}>
{donations.map((donation) => (
<View key={donation.id} style={styles.donationView}>
<View style={styles.donationContent}>
{/* Donation Info */}
<View style={styles.leftColumn}>
<Text style={styles.donationName}>{donation.name}</Text>
<Text style={styles.donationDetail}>
Tujuan: {donation.tujuan}
</Text>
<Text style={styles.donationDetail}>
Catatan: {donation.catatan}
</Text>
<Text style={styles.donationDetail}>
Tanggal: {donation.tanggal}
</Text>
<Text style={styles.donationDetail}>
Waktu: {donation.waktu}
</Text>
</View>
{/* Donation Amount */}
<View style={styles.rightColumn}>
<Text style={styles.donationAmount}>{donation.nominal}</Text>
</View>
</View>
</View>
))}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 20,
padding: 20,
flex: 1,
backgroundColor: "#fff",
},
backButton: {
position: "absolute",
top: 20,
left: 10,
zIndex: 1,
marginTop: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
marginBottom: 5,
marginLeft: 30,
marginTop: 15,
},
historyBox: {
marginTop: 10,
paddingBottom: 5,
},
donationView: {
backgroundColor: "#fff", // Background color for each donation box
borderRadius: 20,
marginVertical: 10,
padding: 15,
flexDirection: "row", // Layout of elements horizontally
justifyContent: "space-between", // Space out left and right columns
alignItems: "center",
borderWidth: 1,
borderColor: "#000",
},
donationContent: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
leftColumn: {
flex: 1,
},
rightColumn: {
alignItems: "flex-end", // Align right side for donation amount
flexDirection: "column",
justifyContent: "center",
},
donationName: {
fontSize: 16,
fontWeight: "bold",
color: "#333",
},
donationDetail: {
fontSize: 14,
color: "#555",
marginBottom: 5,
},
donationAmount: {
fontSize: 18,
fontWeight: "bold",
color: "#4F772D", // Green color for donation amount
},
});

View File

@ -0,0 +1,284 @@
import React, { useState, useEffect } from "react"; // Tambahkan useEffect
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Image,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const StatusPengirimanAdmin = () => {
const navigation = useNavigation();
const [selectedButton, setSelectedButton] = useState("diproses"); // Default to 'diproses'
const [selectedStatus, setSelectedStatus] = useState("diproses"); // Default to 'diproses'
// Data barang
const items = [
{
id: 1,
name: "Tas Kertas",
time: "10 April 2025 - 14:30",
status: "diproses",
imageUri: require("../../../assets/images/tas2.png"),
},
{
id: 2,
name: "Botol",
time: "11 April 2025 - 15:00",
status: "dikirim",
imageUri: require("../../../assets/images/botol1.png"),
},
{
id: 3,
name: "Botol Anak",
time: "12 April 2025 - 16:30",
status: "diterima",
imageUri: require("../../../assets/images/botol2.png"),
},
];
// Effect untuk men-set status saat pertama kali halaman dibuka
useEffect(() => {
setSelectedButton("diproses");
setSelectedStatus("diproses");
}, []);
const handleButtonClick = (status) => {
setSelectedStatus(status);
setSelectedButton(status);
};
// Filter items berdasarkan selected status
const filteredItems = items.filter((item) => item.status === selectedStatus);
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>STATUS PENGIRIMAN</Text>
</View>
{/* Status Buttons */}
<View style={styles.buttonRow}>
<TouchableOpacity
style={[
styles.statusButton,
selectedButton === "diproses" && styles.selectedButton,
]}
onPress={() => handleButtonClick("diproses")}
>
<Ionicons
name="sync"
size={20}
color={selectedButton === "diproses" ? "#fff" : "#000"}
/>
<Text
style={[
styles.buttonText,
selectedButton === "diproses" && { color: "#fff" },
]}
>
Diproses
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.statusButton,
selectedButton === "dikirim" && styles.selectedButton,
]}
onPress={() => handleButtonClick("dikirim")}
>
<Ionicons
name="paper-plane"
size={20}
color={selectedButton === "dikirim" ? "#fff" : "#000"}
/>
<Text
style={[
styles.buttonText,
selectedButton === "dikirim" && { color: "#fff" },
]}
>
Dikirim
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.statusButton,
selectedButton === "diterima" && styles.selectedButton,
]}
onPress={() => handleButtonClick("diterima")}
>
<Ionicons
name="checkmark"
size={20}
color={selectedButton === "diterima" ? "#fff" : "#000"}
/>
<Text
style={[
styles.buttonText,
selectedButton === "diterima" && { color: "#fff" },
]}
>
Diterima
</Text>
</TouchableOpacity>
</View>
{/* Filtered List of Items Based on Selected Status */}
<ScrollView style={styles.itemList}>
{filteredItems.length > 0 ? (
filteredItems.map((item) => (
<View key={item.id} style={styles.itemRow}>
<Image source={item.imageUri} style={styles.itemImage} />
<View style={styles.itemDetails}>
<Text style={styles.itemName}>{item.name}</Text>
<Text style={styles.itemTime}>{item.time}</Text>
</View>
<View style={styles.itemActions}>
<View style={styles.coinButton}>
<Text style={styles.coinButtonText}>500 Koin</Text>
</View>
<TouchableOpacity
style={styles.detailButton}
onPress={() =>
navigation.navigate("DetailPengiriman", { item: item })
}
>
<Text style={styles.detailButtonText}>Lihat Detail</Text>
</TouchableOpacity>
</View>
</View>
))
) : (
<Text style={styles.noItemsText}>
Tidak ada barang dalam status ini.
</Text>
)}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f9f9f9",
padding: 20,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 30,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
},
buttonRow: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 5,
},
statusButton: {
flexDirection: "row",
alignItems: "center",
backgroundColor: "#fff",
borderWidth: 1,
borderColor: "#333",
paddingVertical: 10,
paddingHorizontal: 15,
borderRadius: 20,
width: "30%",
justifyContent: "center",
},
selectedButton: {
backgroundColor: "#2D572C", // Green color for selected button
},
buttonText: {
marginLeft: 5,
fontSize: 14,
color: "#000",
},
itemList: {
marginTop: 20,
},
itemRow: {
flexDirection: "row",
alignItems: "center",
backgroundColor: "#fff",
padding: 15,
marginBottom: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: "#ddd",
},
itemImage: {
width: 60,
height: 60,
backgroundColor: "#fff",
borderRadius: 5,
},
itemDetails: {
flex: 1,
marginLeft: 10,
},
itemName: {
fontSize: 16,
fontWeight: "bold",
color: "#333",
},
itemTime: {
fontSize: 12,
color: "#555",
marginTop: 5,
},
itemActions: {
alignItems: "flex-end",
justifyContent: "center",
},
coinButton: {
backgroundColor: "#2D572C",
paddingVertical: 8,
paddingHorizontal: 15,
borderRadius: 5,
marginBottom: 5,
},
coinButtonText: {
fontSize: 12,
color: "#fff",
},
detailButton: {
backgroundColor: "#ddd",
paddingVertical: 8,
paddingHorizontal: 15,
borderRadius: 25,
},
detailButtonText: {
fontSize: 12,
color: "#333",
},
noItemsText: {
fontSize: 14,
color: "#888",
textAlign: "center",
marginTop: 20,
},
});
export default StatusPengirimanAdmin;

View File

@ -0,0 +1,221 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
TouchableOpacity,
Alert,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Pastikan menggunakan Ionicons yang benar
import { useNavigation } from "@react-navigation/native";
import MapView, { Marker } from "react-native-maps"; // Import MapView
import { Picker } from "@react-native-picker/picker"; // Hanya gunakan ini saja
const TambahTPS = () => {
const navigation = useNavigation();
// State untuk form input
const [namaTPS, setNamaTPS] = useState("");
const [luasTPS, setLuasTPS] = useState("");
const [dayaTampung, setDayaTampung] = useState("");
const [jenisTPS, setJenisTPS] = useState("Container");
const [alamat, setAlamat] = useState("");
const [kecamatan, setKecamatan] = useState("Nganjuk");
const [latitude, setLatitude] = useState(null);
const [longitude, setLongitude] = useState(null);
// Fungsi untuk menangani penyimpanan TPS baru
const handleTambahTPS = () => {
if (
!namaTPS ||
!luasTPS ||
!dayaTampung ||
!alamat ||
!latitude ||
!longitude
) {
Alert.alert("Form belum lengkap", "Mohon lengkapi semua data TPS.");
return;
}
// Aksi penyimpanan TPS baru (misalnya kirim ke backend atau state global)
Alert.alert("Berhasil", "TPS baru berhasil ditambahkan!");
// Kembali ke halaman daftar TPS
navigation.goBack();
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>TAMBAH LOKASI TPS</Text>
</View>
{/* Form Input TPS */}
<View style={styles.formContainer}>
<TextInput
style={styles.input}
placeholder="Nama TPS"
value={namaTPS}
onChangeText={setNamaTPS}
/>
<TextInput
style={styles.input}
placeholder="Luas TPS (m2)"
value={luasTPS}
keyboardType="numeric"
onChangeText={setLuasTPS}
/>
<TextInput
style={styles.input}
placeholder="Daya Tampung"
value={dayaTampung}
keyboardType="numeric"
onChangeText={setDayaTampung}
/>
<Text style={styles.label}>Pilih Jenis TPS</Text>
<Picker
selectedValue={jenisTPS}
style={styles.picker}
onValueChange={(itemValue) => setJenisTPS(itemValue)}
>
<Picker.Item label="Container" value="Container" />
<Picker.Item label="Depo Kecil" value="Depo Kecil" />
</Picker>
{/* Form Detail Lokasi */}
<TextInput
style={styles.input}
placeholder="Alamat"
value={alamat}
onChangeText={setAlamat}
/>
<Text style={styles.label}>Pilih Kecamatan</Text>
<Picker
selectedValue={kecamatan}
style={styles.picker}
onValueChange={(itemValue) => setKecamatan(itemValue)}
>
<Picker.Item label="Nganjuk" value="Nganjuk" />
<Picker.Item label="Bagor" value="Bagor" />
<Picker.Item label="Wilangan" value="Wilangan" />
<Picker.Item label="Baron" value="Baron" />
</Picker>
<TextInput
style={styles.input}
placeholder="Latitude"
value={latitude}
keyboardType="numeric"
onChangeText={setLatitude}
/>
<TextInput
style={styles.input}
placeholder="Longitude"
value={longitude}
keyboardType="numeric"
onChangeText={setLongitude}
/>
{/* Peta */}
{latitude && longitude ? (
<MapView
style={styles.map}
initialRegion={{
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
}}
/>
</MapView>
) : null}
{/* Tombol Simpan */}
<TouchableOpacity style={styles.saveButton} onPress={handleTambahTPS}>
<Text style={styles.saveButtonText}>SIMPAN</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 0,
},
header: {
marginTop: 40,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 20,
},
title: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
},
formContainer: {
marginTop: -15,
padding: 15,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 15,
marginBottom: 12,
fontSize: 14,
},
label: {
fontSize: 14,
fontWeight: "bold",
marginBottom: 5,
},
picker: {
height: 50,
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
marginBottom: 12,
},
map: {
height: 200,
marginBottom: 20,
},
saveButton: {
width: "100%",
padding: 15,
backgroundColor: "#2D572C", // Warna hijau untuk tombol kirim
alignItems: "center",
borderRadius: 15,
},
saveButtonText: {
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
});
export default TambahTPS;

View File

@ -0,0 +1,348 @@
import React, { useState, useEffect } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Image,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import BottomTabAdmin from "../../Navigation/BottomTabAdmin";
const TukarKoin = () => {
const navigation = useNavigation();
const [selectedButton, setSelectedButton] = useState("diproses");
const [selectedStatus, setSelectedStatus] = useState("diproses");
const items = [
{
id: 1,
name: "Tas Kertas",
time: "10 April 2025 - 14:30",
status: "diproses",
imageUri: require("../../assets/images/tas2.png"),
user: {
profileImage: require("../../assets/images/fotoprofil.jpeg"),
fullName: "Budi Santoso",
address: "Jl. Merdeka No.10, Jakarta",
email: "budi@example.com",
},
},
{
id: 2,
name: "Botol",
time: "11 April 2025 - 15:00",
status: "dikirim",
imageUri: require("../../assets/images/botol1.png"),
user: {
profileImage: require("../../assets/images/fotoprofil.jpeg"),
fullName: "Siti Rahma",
address: "Jl. Sudirman No.5, Bandung",
email: "siti@example.com",
},
},
{
id: 3,
name: "Botol Anak",
time: "12 April 2025 - 16:30",
status: "diterima",
imageUri: require("../../assets/images/botol2.png"),
user: {
profileImage: require("../../assets/images/fotoprofil.jpeg"),
fullName: "Ahmad Rizki",
address: "Jl. Raya No.7, Surabaya",
email: "ahmad@example.com",
},
},
];
useEffect(() => {
setSelectedButton("diproses");
setSelectedStatus("diproses");
}, []);
const handleButtonClick = (status) => {
setSelectedStatus(status);
setSelectedButton(status);
};
const filteredItems = items.filter((item) => item.status === selectedStatus);
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<Text style={styles.title}>PENUKARAN KOIN</Text>
</View>
{/* Status Buttons */}
<View style={styles.buttonRow}>
{["diproses", "dikirim", "diterima"].map((status) => (
<TouchableOpacity
key={status}
style={[
styles.statusButton,
selectedButton === status && styles.selectedButton,
]}
onPress={() => handleButtonClick(status)}
>
<Ionicons
name={
status === "diproses"
? "sync"
: status === "dikirim"
? "paper-plane"
: "checkmark"
}
size={20}
color={selectedButton === status ? "#fff" : "#000"}
/>
<Text
style={[
styles.buttonText,
selectedButton === status && { color: "#fff" },
]}
>
{status.charAt(0).toUpperCase() + status.slice(1)}
</Text>
</TouchableOpacity>
))}
</View>
{/* Filtered List of Items */}
<ScrollView contentContainerStyle={styles.itemList}>
{filteredItems.length > 0 ? (
filteredItems.map((item) => (
<View key={item.id} style={styles.itemRow}>
<View style={styles.itemInfo}>
<Image source={item.imageUri} style={styles.itemImage} />
<View style={styles.itemDetails}>
<Text style={styles.itemName}>{item.name}</Text>
<Text style={styles.itemTime}>{item.time}</Text>
</View>
</View>
<View style={styles.itemActions}>
<View style={styles.coinButton}>
<Text style={styles.coinButtonText}>500 Koin</Text>
</View>
<TouchableOpacity
style={styles.detailButton}
onPress={() =>
navigation.navigate("DetailPengirimanAdmin", { item })
}
>
<Text style={styles.detailButtonText}>Lihat Detail</Text>
</TouchableOpacity>
</View>
<View style={styles.userInfo}>
<Image
source={item.user.profileImage}
style={styles.profileImage}
/>
<View style={styles.userDetails}>
<Text style={styles.userName}>{item.user.fullName}</Text>
<Text style={styles.userAddress}>{item.user.address}</Text>
<Text style={styles.userEmail}>{item.user.email}</Text>
</View>
</View>
</View>
))
) : (
<Text style={styles.noItemsText}>
Tidak ada barang dalam status ini.
</Text>
)}
</ScrollView>
{/* Floating Daftar Barang Button */}
<TouchableOpacity
style={styles.floatingButton}
onPress={() => navigation.navigate("DaftarBarang")}
>
<Ionicons name="add-circle-outline" size={24} color="#fff" />
<Text style={styles.floatingButtonText}>Daftar Barang</Text>
</TouchableOpacity>
{/* Bottom Navigation */}
<View style={styles.bottomNavigation}>
<BottomTabAdmin />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f9f9f9",
paddingHorizontal: 20,
paddingTop: 20,
},
header: {
marginTop: 30,
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#333",
},
buttonRow: {
flexDirection: "row",
justifyContent: "space-around",
marginBottom: 25,
},
statusButton: {
flexDirection: "row",
alignItems: "center",
backgroundColor: "#fff",
borderWidth: 1,
borderColor: "#2D572C",
paddingVertical: 12,
paddingHorizontal: 20,
borderRadius: 25,
justifyContent: "center",
width: "30%",
},
selectedButton: {
backgroundColor: "#2D572C",
},
buttonText: {
marginLeft: 10,
fontSize: 14,
color: "#333",
},
itemList: {
paddingBottom: 120,
},
itemRow: {
backgroundColor: "#fff",
padding: 20,
marginBottom: 20,
borderRadius: 15,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 5,
elevation: 3,
},
itemInfo: {
flexDirection: "row",
alignItems: "center",
marginBottom: 15,
},
itemImage: {
width: 80,
height: 80,
backgroundColor: "#fff",
borderRadius: 10,
},
itemDetails: {
flex: 1,
marginLeft: 15,
},
itemName: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
itemTime: {
fontSize: 12,
color: "#777",
marginTop: 5,
},
itemActions: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 15,
},
coinButton: {
backgroundColor: "#2D572C",
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 5,
},
coinButtonText: {
fontSize: 14,
color: "#fff",
},
detailButton: {
backgroundColor: "#ddd",
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 25,
},
detailButtonText: {
fontSize: 14,
color: "#333",
},
userInfo: {
flexDirection: "row",
alignItems: "center",
marginTop: 10,
borderTopWidth: 1,
borderTopColor: "#ddd",
paddingTop: 10,
},
profileImage: {
width: 45,
height: 45,
borderRadius: 25,
},
userDetails: {
marginLeft: 12,
},
userName: {
fontSize: 14,
fontWeight: "bold",
color: "#333",
},
userAddress: {
fontSize: 12,
color: "#555",
},
userEmail: {
fontSize: 12,
color: "#555",
},
noItemsText: {
fontSize: 14,
color: "#888",
textAlign: "center",
marginTop: 30,
},
floatingButton: {
position: "absolute",
bottom: 100,
right: 20,
backgroundColor: "#2D572C",
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 20,
borderRadius: 30,
elevation: 5,
},
floatingButtonText: {
color: "#fff",
fontWeight: "bold",
marginLeft: 6,
},
bottomNavigation: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#fff",
borderTopWidth: 1,
borderTopColor: "#ddd",
},
});
export default TukarKoin;

334
screens/AksesAkun.js Normal file
View File

@ -0,0 +1,334 @@
import React, { useState } from "react";
import {
View,
Text,
TouchableOpacity,
TextInput,
StyleSheet,
Image,
} from "react-native";
import { Ionicons, FontAwesome } from "@expo/vector-icons";
const AksesAkun = ({ navigation }) => {
const [role, setRole] = useState(null);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const handleLogin = () => {
if (!role) {
setErrorMessage("Pilih dulu role Anda (Admin atau Warga)");
return;
}
if (!email || !password) {
setErrorMessage("Masukkan email dan kata sandi dengan benar");
return;
}
if (
role === "admin" &&
email === "admin@gmail.com" &&
password === "1234"
) {
setErrorMessage("");
navigation.navigate("AksesAdminNavigator", { screen: "AdminScreen" });
} else if (
role === "warga" &&
email === "warga@gmail.com" &&
password === "1234"
) {
setErrorMessage("");
navigation.navigate("AksesWargaNavigator", { screen: "Home" });
} else {
setErrorMessage("Email atau kata sandi salah");
}
};
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("Onboarding")}
>
<Ionicons name="arrow-back" size={30} color="#000" />
</TouchableOpacity>
<Image
style={styles.image}
source={require("../assets/images/sampah.png")}
resizeMode="contain"
/>
<Text style={styles.welcomeText}>Selamat Datang kembali,</Text>
<Text style={styles.ecoMapperText}>EcoMapper !</Text>
<Text style={styles.label}>Pilih Akses</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[
styles.roleButton,
role === "admin" && styles.roleButtonSelected,
]}
onPress={() => setRole("admin")}
>
<Ionicons
name="person"
size={24}
color={role === "admin" ? "#fff" : "#000"}
/>
<Text
style={[
styles.roleButtonText,
role === "admin" && styles.roleButtonTextSelected,
]}
>
ADMIN
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.roleButton,
role === "warga" && styles.roleButtonSelected,
]}
onPress={() => setRole("warga")}
>
<Ionicons
name="people"
size={24}
color={role === "warga" ? "#fff" : "#000"}
/>
<Text
style={[
styles.roleButtonText,
role === "warga" && styles.roleButtonTextSelected,
]}
>
WARGA
</Text>
</TouchableOpacity>
</View>
<Text style={styles.label}>Email</Text>
<View style={styles.inputContainer}>
<Ionicons name="mail" size={24} color="gray" style={styles.icon} />
<TextInput
style={styles.input}
placeholder="Masukkan email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
/>
</View>
<Text style={styles.label}>Kata Sandi</Text>
<View style={styles.passwordContainer}>
<FontAwesome name="lock" size={24} color="gray" style={styles.icon} />
<TextInput
style={styles.passwordInput}
placeholder="Masukkan kata sandi"
secureTextEntry={!showPassword}
value={password}
onChangeText={setPassword}
autoCapitalize="none"
/>
<TouchableOpacity
style={styles.eyeIcon}
onPress={() => setShowPassword(!showPassword)}
>
<Ionicons
name={showPassword ? "eye-off" : "eye"}
size={24}
color="gray"
/>
</TouchableOpacity>
</View>
{errorMessage ? (
<Text style={styles.errorText}>{errorMessage}</Text>
) : null}
<TouchableOpacity style={styles.loginButton} onPress={handleLogin}>
<Text style={styles.loginButtonText}>Masuk</Text>
</TouchableOpacity>
{/* "Daftar Sekarang" Text */}
<View style={styles.registerContainer}>
<Text style={styles.registerText}>
Belum punya akun?{" "}
<TouchableOpacity
onPress={() =>
navigation.navigate("AksesWargaNavigator", { screen: "daftar" })
}
>
<Text style={styles.registerLink}>Daftar Sekarang</Text>
</TouchableOpacity>
</Text>
</View>
{/* "Lupa Kata Sandi?" Text */}
<View style={styles.forgotPasswordContainer}>
<TouchableOpacity
onPress={() =>
navigation.navigate("AksesWargaNavigator", { screen: "lupasandi" })
}
>
<Text style={styles.forgotPasswordText}>Lupa Kata Sandi?</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default AksesAkun;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 20,
alignItems: "center",
justifyContent: "center",
},
backButton: {
position: "absolute",
top: 60, // sesuaikan dengan tinggi status bar dan padding
left: 20,
zIndex: 10,
padding: 6,
borderRadius: 6,
backgroundColor: "#fff", // warna soft supaya tombol terlihat
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
},
image: {
width: 300,
height: 200,
marginBottom: 20,
},
welcomeText: {
fontSize: 28,
fontWeight: "bold",
textAlign: "center",
},
ecoMapperText: {
fontSize: 34,
fontWeight: "bold",
color: "#000",
marginBottom: 30,
textAlign: "center",
},
label: {
fontSize: 18,
alignSelf: "flex-start",
marginLeft: 10,
marginBottom: 10,
fontWeight: "600",
},
buttonContainer: {
flexDirection: "row",
marginBottom: 30,
justifyContent: "center",
gap: 15,
},
roleButton: {
flexDirection: "row",
alignItems: "center",
borderWidth: 1,
borderColor: "#000",
borderRadius: 12,
paddingVertical: 15,
paddingHorizontal: 25,
marginHorizontal: 5,
backgroundColor: "#fff",
},
roleButtonSelected: {
backgroundColor: "#2D572C",
borderColor: "#2D572C",
},
roleButtonText: {
fontSize: 20,
fontWeight: "bold",
marginLeft: 8,
color: "#000",
},
roleButtonTextSelected: {
color: "#fff",
},
inputContainer: {
flexDirection: "row",
alignItems: "center",
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 8,
marginBottom: 20,
paddingLeft: 10,
height: 50,
width: "100%",
},
input: {
flex: 1,
fontSize: 16,
},
passwordContainer: {
flexDirection: "row",
alignItems: "center",
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 8,
marginBottom: 40,
paddingLeft: 10,
height: 50,
width: "100%",
},
passwordInput: {
flex: 1,
fontSize: 16,
},
icon: {
marginRight: 10,
},
eyeIcon: {
paddingHorizontal: 10,
},
loginButton: {
backgroundColor: "#2D572C",
paddingVertical: 15,
paddingHorizontal: 160,
borderRadius: 8,
marginBottom: 15,
},
loginButtonText: {
color: "#fff",
textAlign: "center",
fontWeight: "bold",
fontSize: 20,
},
registerContainer: {
marginTop: 10,
},
registerText: {
fontSize: 16,
color: "#333",
},
registerLink: {
color: "#2D572C",
fontWeight: "bold",
},
forgotPasswordContainer: {
marginTop: 10,
},
forgotPasswordText: {
color: "#2D572C",
fontWeight: "bold",
textAlign: "center",
fontSize: 16,
},
errorText: {
color: "red",
fontSize: 15,
marginBottom: 10,
},
});

View File

@ -0,0 +1,225 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Image } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const BerandaPengaduan = () => {
const navigation = useNavigation();
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("Home")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.headerTitle}>BERANDA PENGADUAN</Text>
</View>
{/* First Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Johan Okta Pangestu</Text>
</View>
<Text style={styles.time}>03/01/2025 10.12 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Sedang diverifikasi</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah numpuk di depan masjid - JI Letjen Sparman
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.arenalte.com/uploads/2019/07/sampah.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://www.storypick.com/wp-content/uploads/2019/06/waste.png",
}}
style={styles.reportImage}
/>
</View>
</View>
{/* Second Report */}
<View style={styles.reportContainer}>
<View style={styles.reportHeader}>
<View style={styles.profileContainer}>
<Image
source={{
uri: "https://www.w3schools.com/howto/img_avatar2.png", // Replace with actual profile picture URI
}}
style={styles.profileImage}
/>
<Text style={styles.reporterName}>Jihan Pangesti</Text>
</View>
<Text style={styles.time}>03/01/2025 10.12 WIB</Text>
</View>
<TouchableOpacity style={styles.statusButton}>
<Text style={styles.reportStatus}>Dalam Proses</Text>
</TouchableOpacity>
<Text style={styles.reportDescription}>
Sampah berserakan di Pasar Lama - JI. Sukarno, Nganjuk
</Text>
<Text style={styles.reportNote}>
Catatan: Mohon segera ditindaklanjuti karena sangat mengganggu
masyarakat sekitar.
</Text>
{/* Images */}
<View style={styles.imageContainer}>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-97714168,imgsize-1547670,width-400,resizemode-4/97714168.jpg",
}}
style={styles.reportImage}
/>
<Image
source={{
uri: "https://static.toiimg.com/thumb/msid-87155572,imgsize-1511223,width-400,resizemode-4/87155572.jpg",
}}
style={styles.reportImage}
/>
</View>
{/* Button to contribute */}
<TouchableOpacity
style={styles.contributeButton}
onPress={() => navigation.navigate("KontribusiScreen")}
>
<Text style={styles.contributeText}>Kontribusi Sekarang</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 16,
marginTop: 40,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
marginRight: 10,
},
headerTitle: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
},
reportContainer: {
marginBottom: 20,
padding: 12,
borderRadius: 15,
backgroundColor: "#fff",
borderWidth: 0.5,
borderColor: "#000",
},
reportHeader: {
flexDirection: "row",
justifyContent: "space-between",
paddingBottom: 10,
},
profileContainer: {
flexDirection: "row",
alignItems: "center",
},
profileImage: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 10,
},
reporterName: {
fontSize: 16,
fontWeight: "bold",
},
time: {
fontSize: 14,
color: "#555",
},
statusButton: {
backgroundColor: "#DDD",
borderRadius: 8,
paddingVertical: 5,
paddingHorizontal: 5,
marginVertical: 8,
alignItems: "center",
width: "32%",
borderWidth: 0.5,
},
reportStatus: {
color: "#000",
fontSize: 14,
},
reportDescription: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
reportNote: {
fontSize: 14,
color: "#000",
marginBottom: 12,
},
imageContainer: {
flexDirection: "row",
justifyContent: "flex-start",
marginBottom: 12,
},
reportImage: {
width: 100,
height: 100,
borderRadius: 8,
marginRight: 5,
marginLeft: 5,
},
contributeButton: {
backgroundColor: "#2D572C",
padding: 10,
borderRadius: 8,
alignItems: "center",
width: "50%",
alignContent: "center",
justifyContent: "center",
marginLeft: 90,
marginTop: 20,
},
contributeText: {
color: "#fff",
fontSize: 16,
},
coinText: {
color: "#fff",
fontSize: 14,
},
});
export default BerandaPengaduan;

View File

@ -0,0 +1,236 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
Image,
ScrollView,
StyleSheet,
Alert,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
import BottomNav from "../../Navigation/BottomNav";
const EcoMapCoinExchangeScreen = () => {
const navigation = useNavigation();
const userCoin = 1350;
const expiredDate = "30 Mei 2025";
const items = [
{
id: 1,
name: "Botol Minum",
coin: 300,
image: require("../../assets/images/botol1.png"),
},
{
id: 2,
name: "Botol Minum Anak",
coin: 350,
image: require("../../assets/images/botol2.png"),
},
{
id: 3,
name: "Tas Belanja",
coin: 250,
image: require("../../assets/images/tas2.png"),
},
{
id: 4,
name: "Peralatan Makan",
coin: 400,
image: require("../../assets/images/alatmakan.png"),
},
];
const handleExchange = (item) => {
if (userCoin >= item.coin) {
Alert.alert(
"Konfirmasi Penukaran",
`Anda yakin ingin menukar ${item.coin} koin untuk mendapatkan ${item.name}?`,
[
{ text: "Batal", style: "cancel" },
{
text: "Ya",
onPress: () => {
Alert.alert(
"Berhasil",
`Kamu telah menukar ${item.name} dengan ${item.coin} Koin.`
);
},
},
]
);
} else {
Alert.alert(
"Koin Tidak Cukup",
"Silakan kumpulkan koin terlebih dahulu."
);
}
};
return (
<View style={{ flex: 1, backgroundColor: "#fff" }}>
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.title}>TUKAR KOIN</Text>
<View style={styles.coinBox}>
<View style={styles.coinInfoColumn}>
<Text style={styles.coinAmount}>
<Text style={styles.coinIcon}></Text> {userCoin}{" "}
<Text style={styles.coinText}>Koin EcoMap</Text>
</Text>
<Text style={styles.expiryText}>
{userCoin} Koin EcoMap kadaluwarsa pada {expiredDate}
</Text>
</View>
<View style={styles.coinInfoRow}>
<TouchableOpacity
style={styles.getCoinBtn}
onPress={() => navigation.navigate("misimingguan")}
>
<Text style={styles.getCoinText}>Dapatkan Koin</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.itemGrid}>
{items.map((item) => (
<View key={item.id} style={styles.itemCard}>
<Image source={item.image} style={styles.itemImage} />
<Text style={styles.itemName}>{item.name}</Text>
<View style={styles.coinBoxItem}>
<Text style={styles.itemCoin}>{item.coin} Koin</Text>
</View>
<TouchableOpacity
style={styles.exchangeBtn}
onPress={() => handleExchange(item)}
>
<Text style={styles.exchangeText}>Tukar Koin</Text>
</TouchableOpacity>
</View>
))}
</View>
</ScrollView>
{/* BottomNav harus di luar ScrollView supaya fixed */}
<BottomNav />
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
backgroundColor: "#fff",
width: "100%",
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
marginBottom: 20,
textAlign: "left",
marginLeft: 10,
marginTop: 40,
},
coinBox: {
borderWidth: 1,
borderColor: "#ccc",
padding: 15,
borderRadius: 10,
marginBottom: 20,
alignItems: "center",
flexDirection: "row",
justifyContent: "space-between",
},
coinInfoColumn: {
flexDirection: "column",
justifyContent: "center",
alignItems: "flex-start",
},
coinAmount: {
fontSize: 24,
fontWeight: "bold",
color: "#d4af37",
},
coinIcon: {
fontSize: 22,
},
coinText: {
color: "#2f4f2f",
fontSize: 16,
},
expiryText: {
fontSize: 12,
color: "#888",
marginTop: 5,
},
coinInfoRow: {
justifyContent: "center",
alignItems: "center",
},
getCoinBtn: {
backgroundColor: "#d4af37",
paddingVertical: 6,
paddingHorizontal: 20,
borderRadius: 8,
borderWidth: 1,
borderColor: "#000",
},
getCoinText: {
color: "#fff",
fontWeight: "bold",
},
itemGrid: {
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-between",
},
itemCard: {
width: "48%",
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 12,
padding: 8,
marginBottom: 15,
alignItems: "center",
},
itemImage: {
width: 70,
height: 100,
resizeMode: "contain",
},
itemName: {
marginTop: 10,
fontSize: 20,
fontWeight: "bold",
textAlign: "center",
},
coinBoxItem: {
backgroundColor: "#2D572C",
paddingVertical: 6,
paddingHorizontal: 20,
borderRadius: 8,
marginVertical: 6,
},
itemCoin: {
color: "#fff",
fontWeight: "bold",
fontSize: 18,
textAlign: "center",
},
exchangeBtn: {
backgroundColor: "#e2e2e2",
paddingHorizontal: 10,
paddingVertical: 6,
borderRadius: 6,
borderWidth: 1,
},
exchangeText: {
fontWeight: "bold",
},
});
export default EcoMapCoinExchangeScreen;

415
screens/AksesWarga/Home.js Normal file
View File

@ -0,0 +1,415 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity,
ImageBackground,
Dimensions,
} from "react-native";
import {
Ionicons,
FontAwesome5,
MaterialCommunityIcons,
} from "@expo/vector-icons";
import Carousel from "react-native-reanimated-carousel";
import { useNavigation } from "@react-navigation/native";
import BottomNav from "../../Navigation/BottomNav";
const { width } = Dimensions.get("window"); // Get the screen width
const Home = () => {
// const navigate = (route) => navigation.navigate(route);
const navigation = useNavigation();
const [activeSlide, setActiveSlide] = useState(0);
const sliderData = [
{ id: "1", image: require("../../assets/images/poster1.png") },
{ id: "2", image: require("../../assets/images/poster2.png") },
];
const handleNext = () => {
navigation.navigate(""); // Add the name of the screen to navigate
};
return (
<View style={styles.container}>
<ImageBackground
source={require("../../assets/images/bg.png")}
style={styles.backgroundImage}
>
<View style={styles.header}>
<Text style={styles.date}>05 Mei 2024</Text>
<Text style={styles.greeting}>
HI, PENGGUNA ECOMAP{" "}
<Ionicons name="checkmark-circle" size={18} color="green" />
</Text>
<Text style={styles.subtitle}>
KEBERSIHAN LINGKUNGAN SEKITAR ANDA WAJIB TERJAGA!
</Text>
</View>
<View style={styles.coinRow}>
<View style={styles.coinInfo}>
<View style={styles.coinBox}>
<Text style={styles.coinLabel}>KOIN SAYA</Text>
<View style={styles.coinValueRow}>
<Text style={styles.coinText}>0</Text>
<Image
source={require("../../assets/images/koin.png")}
style={styles.coinImage}
/>
</View>
<Text style={styles.noCoinText}>
Belum ada koin yang terkumpul
</Text>
<TouchableOpacity
style={styles.historyButton}
onPress={() => navigation.navigate("RiwayatCoinScreen")} // Ganti dengan nama layar yang sesuai
>
<Text style={styles.historyButtonText}>RIWAYAT KOIN</Text>
</TouchableOpacity>
</View>
</View>
<TouchableOpacity
style={styles.reportButton}
onPress={() => navigation.navigate("BerandaPengaduan")}
>
<Text style={styles.reportButtonText}>BERANDA PENGADUAN</Text>
</TouchableOpacity>
</View>
<View style={styles.menuContainer}>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("LokasiTerdekat")}
// onPress={() =>
// navigation.navigate("MainTabs", { screen: "LokasiTerdekat" })
// } // Buka MainTabs, lalu LokasiTerdekat
>
<Ionicons
name="location"
size={45}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>LOKASI TERDEKAT</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("daftarTPS")}
>
<Ionicons
name="bookmarks"
size={45}
color="#2C6B2F"
style={styles.menuImage}
/>
<Text style={styles.menuText}>DAFTAR TPS DI NGANJUK</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("pengaduansampah")}
>
<MaterialCommunityIcons
name="trash-can"
size={50}
color="#2C6B2F"
style={styles.menuImage}
/>
{/* <View style={styles.badge}>
<FontAwesome5
name="lock"
size={12}
color="#fff"
style={styles.lock}
/>
</View> */}
<Text style={styles.menuText}>PENGADUAN SAMPAH</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => navigation.navigate("misimingguan")}
>
<FontAwesome5
name="gift"
size={45}
color="#2C6B2F"
style={styles.menuImage}
/>
{/* <View style={styles.badge}>
<FontAwesome5
name="lock"
size={12}
color="#fff"
style={styles.lock}
/>
</View> */}
<Text style={styles.menuText}>DAPATKAN KOIN</Text>
</TouchableOpacity>
</View>
<View style={{ marginTop: 20 }}>
<Carousel
loop
autoPlay={true}
autoPlayInterval={3000}
width={width} // Use screen width here
height={180}
data={sliderData}
scrollAnimationDuration={1000}
onSnapToItem={(index) => setActiveSlide(index)}
renderItem={({ item }) => (
<Image
source={item.image}
style={styles.sliderImage}
resizeMode="cover"
/>
)}
/>
</View>
</ImageBackground>
<BottomNav />
{/* <View style={styles.bottomNav}>
<TouchableOpacity style={styles.navItem}>
<Ionicons name="home" size={30} color="#2C6B2F" />
<Text style={styles.navText}>UTAMA</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => navigation.navigate("EcoMapCoinExchangeScreen")}
>
<FontAwesome5 name="exchange-alt" size={24} color="#2C6B2F" />
<Text style={styles.navText}>TUKAR KOIN</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<View style={styles.notifIconContainer}>
<Ionicons name="notifications-outline" size={24} color="#2C6B2F" />
<View style={styles.badge}>
<Text style={styles.badgeText}>1</Text>
</View>
</View>
<Text style={styles.navText}>NOTIFIKASI</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Ionicons name="person-circle-outline" size={24} color="#2C6B2F" />
<Text style={styles.navText}>PROFIL</Text>
</TouchableOpacity>
</View> */}
</View>
// </View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#f9f9f9" },
backgroundImage: {
flex: 1,
justifyContent: "center",
paddingLeft: 10,
paddingRight: 10,
paddingTop: 0,
},
header: { marginTop: 10, alignItems: "flex-start", paddingBottom: 5 },
date: { fontSize: 20, color: "#000", paddingLeft: 20, marginTop: 20 },
greeting: {
fontSize: 20,
fontWeight: "bold",
marginTop: 0,
color: "#333",
paddingLeft: 20,
},
subtitle: {
fontSize: 15,
color: "#27AE60",
fontWeight: "600",
paddingLeft: 20,
},
coinRow: {
flexDirection: "column",
justifyContent: "flex-start",
alignItems: "center",
paddingHorizontal: 20,
marginTop: 20,
},
coinInfo: { alignItems: "flex-start" },
coinLabel: {
fontSize: 18,
fontWeight: "700",
color: "#333",
marginBottom: 0,
marginLeft: -100,
},
coinBox: {
marginVertical: 10,
backgroundColor: "#fff",
paddingHorizontal: 130,
paddingVertical: 15,
borderRadius: 20,
flexDirection: "column",
alignItems: "flex-start",
elevation: 1,
borderWidth: 1,
borderColor: "#aaa",
position: "relative",
},
coinValueRow: { flexDirection: "row", alignItems: "center", marginTop: 10 },
coinText: {
fontSize: 30,
fontWeight: "bold",
color: "#333",
textAlign: "left",
marginLeft: -100,
},
coinImage: { width: 24, height: 24, marginLeft: 6 },
noCoinText: {
fontSize: 12,
color: "#aaa",
marginTop: 5,
textAlign: "left",
marginLeft: -100,
},
historyButton: {
position: "absolute",
backgroundColor: "#27AE60", // Sesuaikan dengan warna yang diinginkan
paddingVertical: 10,
paddingHorizontal: 10,
borderRadius: 20,
top: -6,
right: 10,
marginTop: 15, // Spasi antara tombol dan teks
alignItems: "center",
justifyContent: "center",
width: "100%", // Lebar penuh box
elevation: 1, // Tambahkan sedikit bayangan
},
historyButtonText: {
fontSize: 14,
fontWeight: "bold",
color: "#fff",
textAlign: "center",
},
reportButton: {
backgroundColor: "#DCDCDC",
paddingVertical: 15, // Adjust padding for a more rectangular shape
paddingHorizontal: 10, // Increase horizontal padding to make it look like a rectangle
borderRadius: 20, // Keep the border radius low for a rectangular shape
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
borderColor: "#999",
width: "80%", // Take up full width inside the box
marginTop: 10,
paddingLeft: 5, // Add some spacing between the content
},
reportButtonText: {
fontSize: 14,
color: "#000",
fontWeight: "bold",
textAlign: "center",
},
menuImage: {
width: 50,
height: 50,
marginLeft: 3,
marginBottom: 5,
marginTop: 7,
justifyContent: "center",
},
menuContainer: {
marginTop: 5,
marginRight: 5,
marginLeft: 12,
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-around",
paddingRight: 15,
},
menuItem: {
width: "23%",
alignItems: "center",
marginVertical: 10,
padding: 10,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 25,
backgroundColor: "#fff",
elevation: 2,
},
menuText: {
fontSize: 12,
fontWeight: "500",
color: "#333",
marginTop: 8,
textAlign: "center",
},
sliderImage: {
height: 160,
borderRadius: 19,
width: "80%",
alignSelf: "center",
marginRight: 25,
},
bottomNav: {
position: "absolute",
bottom: -10,
width: "100%",
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
navItem: {
alignItems: "center",
padding: 6,
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 5,
marginHorizontal: 5,
},
navText: { color: "#2C6B2F", fontSize: 12, marginTop: 5 },
notifIconContainer: { position: "relative" },
badge: {
position: "absolute",
right: -5,
top: -5,
backgroundColor: "#E74C3C",
borderRadius: 10,
paddingHorizontal: 6,
paddingVertical: 2,
},
lock: {
position: "absolute",
right: -5,
top: -5,
backgroundColor: "#2C6B2F",
borderRadius: 40,
paddingHorizontal: 8,
paddingVertical: 5,
borderWidth: 1,
},
badgeText: { color: "#fff", fontSize: 10, fontWeight: "bold" },
});
export default Home;

View File

@ -0,0 +1,114 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
Dimensions,
TouchableOpacity,
} from "react-native";
import MapView, { Marker } from "react-native-maps";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
// Koordinat awal Nganjuk (misal: Alun-Alun Nganjuk)
const initialRegion = {
latitude: -7.6079,
longitude: 111.903,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
// Contoh lokasi TPS di Nganjuk
const locations = [
{ id: 1, name: "TPS Alun-Alun", latitude: -7.6085, longitude: 111.9012 },
{
id: 2,
name: "TPS Jl. Gatot Subroto",
latitude: -7.6102,
longitude: 111.9051,
},
{ id: 3, name: "TPS Pasar Wage", latitude: -7.6055, longitude: 111.9083 },
];
const LokasiTerdekat = () => {
const navigation = useNavigation();
const [region, setRegion] = useState(initialRegion);
return (
<View style={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.navigate("Home")}
>
<Ionicons name="arrow-back" size={28} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>LOKASI TERDEKAT</Text>
<View style={{ width: 28 }} /> {/* Spacer untuk keseimbangan header */}
</View>
{/* MapView */}
<MapView
style={styles.map}
region={region}
onRegionChangeComplete={(newRegion) => setRegion(newRegion)}
>
{locations.map((location) => (
<Marker
key={location.id}
coordinate={{
latitude: location.latitude,
longitude: location.longitude,
}}
title={location.name}
description={`Lat: ${location.latitude}, Lng: ${location.longitude}`}
/>
))}
</MapView>
{/* Deskripsi */}
<Text style={styles.description}>
Menampilkan lokasi TPS terdekat di wilayah Nganjuk.
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
paddingTop: 40,
},
header: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: 16,
marginBottom: 10,
},
backButton: {
padding: 8,
},
title: {
fontSize: 22,
fontWeight: "bold",
textAlign: "left",
marginRight: 160,
},
map: {
width: Dimensions.get("window").width,
height: 800,
// width: 500,
},
description: {
fontSize: 16,
color: "#555",
marginTop: 16,
textAlign: "center",
paddingHorizontal: 16,
},
});
export default LokasiTerdekat;

View File

@ -0,0 +1,164 @@
import React from "react";
import { View, Text, StyleSheet, ScrollView } from "react-native";
import { Ionicons, MaterialIcons } from "@expo/vector-icons"; // Importing icons
import { useNavigation } from "@react-navigation/native";
import BottomNav from "../../Navigation/BottomNav";
const NotifikasiScreen = () => {
const navigation = useNavigation();
const currentDate = new Date();
const formattedDate = `${currentDate.toLocaleDateString()} ${currentDate.toLocaleTimeString()}`;
return (
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{/* Back Button */}
<View>
<Text style={styles.title}>NOTIFIKASI</Text>
</View>
{/* Notification 1: New Report */}
<View style={styles.notification}>
<MaterialIcons name="notifications" size={24} color="#ff9f00" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>Ada laporan baru!</Text>
<Text style={styles.notificationDescription}>
Tim kami sedang meninjau pengaduan sampah terbaru. Terima kasih
atas partisipasi Anda!
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 2: New Trash Pickup Location */}
<View style={styles.notification}>
<Ionicons name="location-sharp" size={24} color="#27ae60" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
TPS baru telah ditambahkan!
</Text>
<Text style={styles.notificationDescription}>
Sekarang Anda bisa menemukan lebih banyak lokasi pembuangan sampah
terdekat di EcoMap.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 3: Duplicate Example */}
<View style={styles.notification}>
<Ionicons name="location-sharp" size={24} color="#27ae60" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
TPS baru telah ditambahkan!
</Text>
<Text style={styles.notificationDescription}>
Sekarang Anda bisa menemukan lebih banyak lokasi pembuangan sampah
terdekat di EcoMap.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
{/* Notification 4: Another Example */}
<View style={styles.notification}>
<Ionicons name="location-sharp" size={24} color="#27ae60" />
<View style={styles.notificationText}>
<Text style={styles.notificationTitle}>
TPS baru telah ditambahkan!
</Text>
<Text style={styles.notificationDescription}>
Sekarang Anda bisa menemukan lebih banyak lokasi pembuangan sampah
terdekat di EcoMap.
</Text>
<Text style={styles.notificationDate}>{formattedDate}</Text>
</View>
</View>
</ScrollView>
{/* Bottom Navigation */}
<View
style={{
position: "absolute",
bottom: 0,
left: 0, // kasih sedikit ruang kiri supaya agak geser ke kanan
right: 0, // beri ruang kanan biar tidak penuh
height: 60,
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
}}
>
<BottomNav />
</View>{" "}
{/* Pastikan tag View ditutup dengan benar */}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // Flex untuk menutupi seluruh layar
backgroundColor: "#f9f9f9",
paddingHorizontal: 20,
paddingTop: 20,
},
scrollContainer: {
flex: 1, // Agar ScrollView mengisi ruang yang tersisa
},
backButtonContainer: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
},
backButton: {
flexDirection: "row",
alignItems: "center",
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
marginLeft: 10,
marginBottom: 20,
marginTop: 40,
},
notification: {
flexDirection: "row",
alignItems: "center",
backgroundColor: "#fff",
padding: 15,
marginBottom: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: "#ddd",
},
notificationText: {
marginLeft: 15,
flex: 1,
},
notificationTitle: {
fontSize: 16,
fontWeight: "bold",
color: "#333",
},
notificationDescription: {
fontSize: 14,
color: "#555",
},
notificationDate: {
fontSize: 12,
color: "#888", // Lighter color for date
marginTop: 5,
},
});
export default NotifikasiScreen;

View File

@ -0,0 +1,206 @@
import React from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
Alert,
Share,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import BottomNav from "../../Navigation/BottomNav";
const ProfilScreen = () => {
const navigation = useNavigation();
const handleLogout = () => {
Alert.alert("Konfirmasi", "Anda yakin ingin keluar?", [
{ text: "Batal" },
{ text: "Keluar", onPress: () => navigation.replace("AksesAkun") },
]);
};
const handleShare = async () => {
try {
await Share.share({
message: "Lihat aplikasi lingkungan ini!",
});
} catch (error) {
console.error("Error sharing: ", error);
}
};
return (
<View style={styles.container}>
{/* Header dengan Foto Profil */}
<View style={styles.header}>
<View style={styles.profileInfo}>
<Image
source={require("../../assets/images/fotoprofil.jpeg")}
style={styles.profileImage}
/>
<Text style={styles.profileName}>Hi Dina 👋</Text>
<Text style={styles.environmentStatus}>
Terus jaga lingkungan sekitar agar tetap hijau dan asri! 🌱
</Text>
</View>
</View>
{/* Info dan Motivasi */}
<View style={styles.motivationSection}>
<Text style={styles.motivationText}>PAHLAWAN LINGKUNGAN</Text>
</View>
{/* Tombol dan Informasi */}
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.navigate("InformasiPribadiStackScreen", {
screen: "InformasiPribadi",
});
}}
>
<Ionicons name="person-outline" size={24} color="black" />
<Text style={styles.buttonText}>Informasi Pribadi</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.navigate("StatusPenukaranKoinStackScreen", {
screen: "StatusPengirimanScreen",
});
}}
>
<Ionicons name="cash-outline" size={24} color="black" />
<Text style={styles.buttonText}>Status Penukaran Koin</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.navigate("StatusPengaduanStack", {
screen: "StatusPengaduanStack",
});
}}
>
<Ionicons name="alert-circle-outline" size={24} color="black" />
<Text style={styles.buttonText}>Status Pengaduan</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.replace("DonasiStackScreen");
}}
>
<Ionicons name="heart-outline" size={24} color="black" />
<Text style={styles.buttonText}>Donasi</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={handleShare}>
<Ionicons name="share-social-outline" size={24} color="black" />
<Text style={styles.buttonText}>Bagikan ke Media Sosial</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={handleLogout}>
<Ionicons name="log-out-outline" size={24} color="black" />
<Text style={styles.buttonText}>Keluar Akun</Text>
</TouchableOpacity>
</View>
{/* Bottom Navigation */}
<View style={styles.bottomNavContainer}>
<BottomNav />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 20,
},
profileImage: {
width: 150,
height: 150,
borderRadius: 100,
borderWidth: 5,
borderColor: "#388e3c",
marginBottom: 10,
marginTop: 50,
},
profileInfo: {
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
},
profileName: {
fontSize: 24,
fontWeight: "bold",
color: "#000",
},
environmentStatus: {
fontSize: 16,
color: "#2e7d32",
marginTop: 5,
fontStyle: "italic",
},
motivationSection: {
marginTop: 10,
backgroundColor: "#f0f0f0",
padding: 10,
borderRadius: 12,
marginBottom: 10,
marginRight: 100,
marginLeft: 100,
borderWidth: 0.5,
},
motivationText: {
fontSize: 15,
color: "#000",
textAlign: "center",
fontWeight: "600",
},
buttonContainer: {
marginTop: 20,
marginLeft: 10,
},
button: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: "#ddd",
},
buttonText: {
marginLeft: 10,
fontSize: 16,
color: "#333",
},
bottomNavContainer: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
height: 60,
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "#fff",
paddingVertical: 8,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
shadowColor: "#000",
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 5,
},
});
export default ProfilScreen;

View File

@ -0,0 +1,148 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
ScrollView,
StyleSheet,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Import Ionicons untuk icon kembali
import { useNavigation } from "@react-navigation/native";
const transactions = [
{
id: 1,
type: "Penukaran Koin",
amount: -250,
date: "2025-04-25 10:30",
description: "Tukar dengan Tas Belanja",
},
{
id: 2,
type: "Penukaran Koin",
amount: -150,
date: "2025-04-26 14:00",
description: "Tukar dengan Botol Minum",
},
{
id: 3,
type: "Penukaran Koin",
amount: -350,
date: "2025-04-27 08:15",
description: "Tukar dengan Peralatan Makan",
},
];
export default function RiwayatCoinScreen() {
const navigation = useNavigation();
return (
<ScrollView contentContainerStyle={styles.container}>
{/* Tombol Kembali */}
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()} // Kembali ke halaman sebelumnya
>
<Ionicons name="arrow-back" size={30} color="#000" />
</TouchableOpacity>
{/* Judul */}
<Text style={styles.title}>RIWAYAT KOIN</Text>
{/* Kolom Riwayat Transaksi */}
<View style={styles.historyBox}>
{transactions.map((transaction) => (
<View key={transaction.id} style={styles.transactionView}>
<View style={styles.transactionContent}>
{/* Deskripsi Transaksi */}
<View style={styles.leftColumn}>
<Text style={styles.transactionType}>{transaction.type}</Text>
<Text style={styles.transactionDescription}>
{transaction.description}
</Text>
<Text style={styles.transactionDate}>{transaction.date}</Text>
</View>
{/* Jumlah Koin */}
<View style={styles.rightColumn}>
<Text style={styles.transactionAmount}>
{transaction.amount} Koin
</Text>
</View>
</View>
</View>
))}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
flex: 1,
backgroundColor: "#fff",
},
backButton: {
position: "absolute",
top: 20,
left: 10,
zIndex: 1,
marginTop: 30,
// Menempatkan tombol di atas komponen lainnya
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
marginBottom: 5,
textAlign: "center",
marginRight: 200,
marginTop: 30,
},
historyBox: {
marginTop: 10,
paddingBottom: 5,
},
transactionView: {
backgroundColor: "#fff", // Warna latar belakang kotak
borderRadius: 20,
marginVertical: 10,
padding: 15,
flexDirection: "row", // Menyusun elemen secara horizontal
justifyContent: "space-between", // Membuat kedua kolom terpisah
alignItems: "center",
borderWidth: 1,
borderColor: "#000",
},
transactionContent: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
leftColumn: {
flex: 1,
},
rightColumn: {
alignItems: "flex-end", // Memposisikan kanan
flexDirection: "column",
justifyContent: "center",
},
transactionType: {
fontSize: 16,
fontWeight: "bold",
color: "#333",
},
transactionDescription: {
fontSize: 14,
color: "#555",
marginBottom: 5,
},
transactionDate: {
fontSize: 12,
color: "#888",
},
transactionAmount: {
fontSize: 24,
fontWeight: "bold",
color: "#4F772D", // Warna merah untuk pengurangan koin
},
});

View File

@ -0,0 +1,305 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ScrollView,
Image,
} from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import { useNavigation } from "@react-navigation/native";
const users = [
{ name: "Diana Fitri Nur Aini", coins: 5000, rank: 1, color: "#A30000" },
{ name: "Revan Ilyas Fatoni", coins: 4800, rank: 2, color: "#FFD700" },
{ name: "Alena Syahwa", coins: 4350, rank: 3, color: "#228B22" },
{ name: "Dina Dwi Anisa", coins: 0, rank: "-", color: "#aaa" },
];
const misimingguan = () => {
const navigation = useNavigation();
const [completedDays, setCompletedDays] = useState([]);
const [totalCoins, setTotalCoins] = useState(0);
// Function to mark a day as completed
const handleDayClick = (day, points) => {
if (!completedDays.includes(day)) {
setCompletedDays([...completedDays, day]);
setTotalCoins(totalCoins + points);
}
};
// Check if the day is completed once
const isCompleted = (day) => completedDays.includes(day);
return (
<ScrollView contentContainerStyle={styles.container}>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity
onPress={() => navigation.navigate("Home")}
style={styles.backButton}
>
<Icon name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<View style={styles.headerTitle}>
<Text style={styles.titleText}>DAPATKAN KOIN</Text>
</View>
</View>
{/* Subtitle */}
<Text style={styles.subTitle}>
Dapatkan Koin <Text style={{ color: "red" }}>LEBIH BANYAK</Text>
</Text>
<Text style={styles.koinText}>
Koin Terkumpul{" "}
<Text style={{ fontWeight: "bold" }}>{totalCoins} / 2600</Text>
</Text>
{/* Daily Check-in */}
<Text style={styles.dailyCheckinLabel}>KUNJUNGI TIAP HARI</Text>
<View style={styles.checkinRow}>
{[
{ day: "Hari-1", point: 10 },
{ day: "Hari-2", point: 15 },
{ day: "Hari-3", point: 20 },
{ day: "Hari-4", point: 25 },
{ day: "Hari-5", point: 30 },
{ day: "Hari-6", point: 35 },
{ day: "Hari-7", point: 50 },
].map((item, index) => (
<TouchableOpacity
key={index}
style={styles.checkinItem}
onPress={() => handleDayClick(item.day, item.point)}
disabled={isCompleted(item.day)}
>
<View
style={[
styles.flameIcon,
isCompleted(item.day) && styles.completedItem,
]}
>
<Text
style={[
styles.pointText,
isCompleted(item.day) && styles.completedPointText,
]}
>
{item.point}
</Text>
<Icon
name="flame"
size={20}
color={isCompleted(item.day) ? "gray" : "red"}
/>
</View>
<Text style={styles.dayText}>{item.day}</Text>
</TouchableOpacity>
))}
</View>
{/* Missions as buttons */}
<View style={styles.missionContainer}>
<MissionButton
point="1000"
label="KONTRIBUSI PENGADUAN SAMPAH"
icon="person"
/>
<MissionButton point="800" label="DONASI" icon="cash" />
<MissionButton point="750" label="PENGADUAN SAMPAH" icon="trash" />
</View>
{/* Top 3 Users */}
<View style={styles.container}>
<Text style={styles.title}>TOP 3 KOIN TERBANYAK</Text>
{users.map((user, index) => (
<View key={index} style={styles.userCard}>
<Icon name="person-circle" size={40} color="#ccc" />
<View style={styles.userInfo}>
<Text style={styles.name}>{user.name}</Text>
<View style={styles.coinRow}>
<Icon name="cash-outline" size={16} color="#FFC107" />
<Text style={styles.coinText}>{user.coins}</Text>
</View>
</View>
<View style={styles.rankBox}>
<Text style={styles.rankNumber}>{user.rank}</Text>
<Icon name="ribbon" size={20} color={user.color} />
</View>
</View>
))}
<Text style={styles.footerText}>
"Ayo kumpulkan lebih banyak koin dengan berkontribusi aktif!{"\n"}
Semakin banyak kamu membantu, semakin besar dampaknya{"\n"}
untuk lingkungan kita!"
</Text>
</View>
</ScrollView>
);
};
const MissionButton = ({ point, label, icon }) => (
<TouchableOpacity style={styles.missionButton}>
<Text style={styles.koinBox}>{point}</Text>
<Icon name={icon} size={32} color="#333" />
<Text style={styles.missionText}>{label}</Text>
</TouchableOpacity>
);
const styles = StyleSheet.create({
container: {
padding: 16,
backgroundColor: "#fff",
marginTop: 40,
flex: 1,
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 12,
},
headerTitle: {
flexDirection: "row",
alignItems: "center",
marginLeft: 12,
},
titleText: {
fontSize: 22,
fontWeight: "bold",
marginLeft: 6,
},
subTitle: {
fontSize: 16,
marginVertical: 6,
},
koinText: {
textAlign: "right",
fontSize: 16,
color: "#555",
},
dailyCheckinLabel: {
textAlign: "center",
marginVertical: 15,
fontWeight: "bold",
color: "#000",
},
checkinRow: {
flexDirection: "row",
justifyContent: "space-evenly",
marginBottom: 28,
},
checkinItem: {
alignItems: "center",
width: 50,
},
flameIcon: {
alignItems: "center",
backgroundColor: "#fff0f0",
borderRadius: 10,
padding: 9,
borderWidth: 1,
},
completedItem: {
opacity: 0.5, // Lower opacity for completed item
},
pointText: {
fontWeight: "bold",
color: "#2D572C",
fontSize: 12,
},
completedPointText: {
color: "gray", // Change point color to gray when completed
},
dayText: {
fontSize: 10,
color: "#444",
marginTop: 4,
},
missionContainer: {
flexDirection: "row",
justifyContent: "space-evenly",
marginBottom: 10,
flexWrap: "wrap",
},
missionButton: {
width: "30%",
backgroundColor: "#fFF",
borderRadius: 12,
padding: 12,
alignItems: "center",
marginBottom: 12,
justifyContent: "center",
borderWidth: 1,
},
koinBox: {
backgroundColor: "#ffeb3b",
justifyContent: "space-evenly",
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 10,
fontWeight: "bold",
marginBottom: 6,
borderWidth: 0.5,
},
missionText: {
textAlign: "center",
fontSize: 11,
marginTop: 6,
},
title: {
textAlign: "center",
fontWeight: "bold",
fontSize: 18,
color: "#2D572C",
marginBottom: 10,
borderBottomWidth: 1,
borderTopWidth: 1,
paddingVertical: 8,
borderColor: "#ccc",
},
userCard: {
flexDirection: "row",
alignItems: "center",
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 12,
padding: 10,
marginBottom: 12,
},
userInfo: {
flex: 1,
marginLeft: 12,
},
name: {
fontWeight: "bold",
fontSize: 14,
},
coinRow: {
flexDirection: "row",
alignItems: "center",
marginTop: 4,
},
coinText: {
marginLeft: 4,
fontSize: 13,
color: "#555",
},
rankBox: {
alignItems: "center",
},
rankNumber: {
fontWeight: "bold",
fontSize: 14,
marginBottom: 2,
},
footerText: {
marginTop: 10,
textAlign: "center",
fontSize: 13,
color: "#444",
},
});
export default misimingguan;

77
screens/DaftarBerhasil.js Normal file
View File

@ -0,0 +1,77 @@
import React from "react";
import { View, Text, Button, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
const KontribusiBerhasil = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={styles.content}>
<MaterialCommunityIcons name="cloud-check" size={140} color="white" />
<Text style={styles.title}>Daftar Berhasil !</Text>
<Text style={styles.subMessage}>
Silahkan masuk untuk mencoba fitur yang ada di EcoMap!
</Text>
<TouchableOpacity
style={styles.button}
// onPress={() => console.log("Daftar Submit")}
onPress={() => navigation.navigate("AksesAkun")}
>
<Text style={styles.buttonText}>MASUK</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap
},
content: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk efek overlay
padding: 30,
borderRadius: 15,
width: "100%",
alignItems: "center",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#fff",
marginTop: 0,
},
message: {
fontSize: 16,
color: "#fff",
textAlign: "center",
marginTop: 10,
},
subMessage: {
fontSize: 15,
color: "#fff",
textAlign: "center",
marginTop: 10,
padding: 3,
},
button: {
backgroundColor: "#fff",
paddingVertical: 10,
paddingHorizontal: 40,
borderRadius: 5,
marginTop: 20,
borderRadius: 25,
fontWeight: "bold",
},
buttonText: {
fontWeight: "bold",
fontSize: 15,
},
});
export default KontribusiBerhasil;

View File

@ -0,0 +1,30 @@
// import React from "react";
// import { createStackNavigator } from "@react-navigation/stack";
// import Home from "./screens/AksesWarga/Home";
// import pengaduansampah from "./screens/PengaduanWarga/pengaduansampah";
// import DetailPengaduan from "./screens/PengaduanWarga/DetailPengaduan";
// const Stack = createStackNavigator();
// export default function HomeStackNavigator() {
// return (
// <Stack.Navigator initialRouteName="Home">
// <Stack.Screen
// name="Home"
// component={Home}
// options={{ headerShown: false }}
// />
// <Stack.Screen
// name="pengaduansampah"
// component={pengaduansampah}
// options={{ headerShown: false }}
// />
// <Stack.Screen
// name="DetailPengaduan"
// component={DetailPengaduan}
// options={{ headerShown: false }}
// />
// </Stack.Navigator>
// );
// }

227
screens/MasukAdmin.js Normal file
View File

@ -0,0 +1,227 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ScrollView,
StatusBar,
Image,
} from "react-native";
import { Ionicons, FontAwesome } from "@expo/vector-icons"; // Import FontAwesome untuk ikon surat
import { useNavigation } from "@react-navigation/native";
// import AksesWargaNavigator from "../Navigation/AksesWargaNavigator";
const MasukAdmin = () => {
const navigation = useNavigation();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
return (
<ScrollView style={{ flex: 1, backgroundColor: "#fff" }}>
<StatusBar backgroundColor={"#fff"} barStyle={"dark-content"} />
<View style={{ flex: 1, backgroundColor: "#fff" }}>
<View
style={{
backgroundColor: "#fff",
paddingVertical: 20,
paddingHorizontal: 10,
flexDirection: "row",
alignItems: "center",
}}
>
{/* Tombol Kembali */}
<TouchableOpacity
onPress={() => navigation.navigate("AksesAkun")}
style={{ width: 45, height: 45, marginRight: 13 }}
>
<Ionicons name="arrow-back" size={30} color="#000" />
</TouchableOpacity>
</View>
<View style={{ justifyContent: "center", alignItems: "center" }}>
<Image
source={require("../assets/images/sampah.png")}
style={{
width: 250,
height: 300,
marginTop: 10,
marginBottom: 10,
marginLeft: 10,
marginRight: 10,
}}
/>
<Text
style={{
color: "#000",
fontWeight: "bold",
fontSize: 40,
textAlign: "left",
}}
>
Selamat Datang
</Text>
<Text
style={{
color: "#000",
fontWeight: "bold",
fontSize: 40,
textAlign: "center",
}}
>
Ecomapper!
</Text>
</View>
</View>
<View style={styles.formContainer}>
<Text style={styles.label}>Email</Text>
<View style={styles.inputContainer}>
<Ionicons name="mail" size={24} color="gray" style={styles.icon} />
<TextInput
style={styles.input}
value={email}
onChangeText={setEmail}
placeholder="Masukkan email"
keyboardType="email-address"
/>
</View>
<Text style={styles.label}>Kata Sandi</Text>
<View style={styles.passwordContainer}>
<FontAwesome name="lock" size={24} color="gray" style={styles.icon} />
<TextInput
style={styles.passwordInput}
value={password}
onChangeText={setPassword}
placeholder="Masukkan Kata Sandi"
secureTextEntry={!showPassword}
/>
<TouchableOpacity
onPress={() => setShowPassword(!showPassword)}
style={styles.eyeIcon}
>
<Ionicons
name={showPassword ? "eye-off" : "eye"}
size={24}
color="gray"
/>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.button}
onPress={() =>
navigation.navigate("AksesAdminNavigator", {
screen: "AdminScreen",
})
}
>
<Text style={styles.buttonText}>Masuk</Text>
</TouchableOpacity>
{/* "Daftar Sekarang" Text */}
<View style={styles.registerContainer}>
<Text style={styles.registerText}>
Belum punya akun?{" "}
<TouchableOpacity onPress={() => navigation.navigate("daftar")}>
<Text style={styles.registerLink}>Daftar Sekarang</Text>
</TouchableOpacity>
</Text>
</View>
{/* "Lupa Kata Sandi?" Text */}
<View style={styles.forgotPasswordContainer}>
<TouchableOpacity
onPress={() => navigation.navigate("lupakatasandi")}
>
<Text style={styles.forgotPasswordText}>Lupa Kata Sandi?</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
formContainer: {
paddingHorizontal: 30,
marginTop: 20,
marginBottom: 30,
},
label: {
fontSize: 16,
marginBottom: 10,
color: "#333",
},
inputContainer: {
flexDirection: "row",
alignItems: "center",
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 5,
marginBottom: 20,
},
input: {
flex: 1,
height: 45,
paddingLeft: 10,
},
icon: {
paddingLeft: 10,
},
passwordContainer: {
flexDirection: "row",
alignItems: "center",
borderColor: "#ddd",
height: 45,
borderWidth: 1,
borderRadius: 5,
marginBottom: 20,
},
passwordInput: {
flex: 1,
height: 45,
paddingLeft: 10,
},
eyeIcon: {
paddingRight: 10,
},
button: {
backgroundColor: "#2D572C",
paddingVertical: 15,
borderRadius: 5,
marginTop: 20,
},
buttonText: {
textAlign: "center",
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
registerContainer: {
marginTop: 15,
alignItems: "center",
},
registerText: {
fontSize: 16,
color: "#333",
},
registerLink: {
color: "#2D572C",
fontWeight: "bold",
},
forgotPasswordContainer: {
marginTop: 15,
alignItems: "center",
},
forgotPasswordText: {
fontSize: 16,
color: "#2D572C",
fontWeight: "bold",
},
});
export default MasukAdmin;

139
screens/Onboarding.js Normal file
View File

@ -0,0 +1,139 @@
import React, { useRef, useEffect, useState } from "react";
import {
View,
Text,
Image,
FlatList,
Dimensions,
StyleSheet,
TouchableOpacity,
} from "react-native";
import { useNavigation } from "@react-navigation/native"; // Mengimpor useNavigation
const { width } = Dimensions.get("window");
const slides = [
{
id: "1",
image: require("../assets/images/onboarding1.png"),
text: "Temukan lokasi tempat pembuangan sampah terdekat.",
},
{
id: "2",
image: require("../assets/images/onboarding2.png"),
text: "Laporkan sampah dan bantu lingkungan jadi lebih bersih.",
},
{
id: "3",
image: require("../assets/images/onboarding3.png"),
text: "Tukar poinmu dengan barang bermanfaat untuk sehari-hari.",
},
];
const Onboarding = () => {
const flatListRef = useRef(null);
const [currentIndex, setCurrentIndex] = useState(0);
const navigation = useNavigation(); // Mendapatkan objek navigasi
useEffect(() => {
const interval = setInterval(() => {
if (currentIndex < slides.length - 1) {
flatListRef.current?.scrollToIndex({
index: currentIndex + 1,
animated: true,
});
}
}, 1000);
return () => clearInterval(interval);
}, [currentIndex]);
const handleNext = () => {
navigation.navigate("AksesAkun"); // Mengarahkan ke layar "AksesAkun"
};
const renderItem = ({ item }) => (
<View style={styles.slide}>
<Image source={item.image} style={styles.image} resizeMode="contain" />
<Text style={styles.text}>{item.text}</Text>
</View>
);
const onViewableItemsChanged = useRef(({ viewableItems }) => {
if (viewableItems.length > 0) {
setCurrentIndex(viewableItems[0].index);
}
}).current;
const viewConfigRef = useRef({ viewAreaCoveragePercentThreshold: 50 });
return (
<View style={styles.container}>
<FlatList
ref={flatListRef}
data={slides}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
renderItem={renderItem}
keyExtractor={(item) => item.id}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewConfigRef.current}
/>
<View style={styles.dotsContainer}>
{slides.map((_, index) => (
<View
key={index}
style={[styles.dot, index === currentIndex && styles.activeDot]}
/>
))}
</View>
{currentIndex === slides.length - 1 && (
<TouchableOpacity style={styles.nextButton} onPress={handleNext}>
<Text style={styles.nextText}>LANJUT</Text>
</TouchableOpacity>
)}
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#fff", marginBottom: 0 },
slide: { width, alignItems: "center", justifyContent: "center", padding: 20 },
image: { width: 250, height: 250, marginBottom: 30 },
text: {
fontSize: 18,
color: "#000",
textAlign: "center",
paddingHorizontal: 20,
},
dotsContainer: {
flexDirection: "row",
justifyContent: "center",
marginBottom: 40,
},
dot: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: "#aaa",
marginHorizontal: 5,
},
activeDot: { backgroundColor: "#435739" },
nextButton: {
position: "absolute",
bottom: 50,
alignSelf: "flex-end",
backgroundColor: "#435739",
paddingHorizontal: 26,
paddingVertical: 16,
elevation: 3,
borderRadius: 10,
marginHorizontal: 20,
},
nextText: { color: "#fff", fontSize: 18, fontWeight: "bold" },
});
export default Onboarding;

View File

@ -0,0 +1,184 @@
import React from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
const pengaduanData = {
id: 1,
judul: "Sampah Menumpuk di Jalan Raya",
alamat: "Jl. Raya No. 25, Desa Suka Maju, Nganjuk",
catatan: "Mohon segera dibersihkan, sudah terlalu lama menumpuk.",
tanggal: "2025-04-28",
gambar: "https://via.placeholder.com/150", // Ganti dengan gambar yang sesuai
status: "Sedang Diproses", // Bisa diganti dengan 'Sedang Diverifikasi', 'Ditolak', dll.
pelapor: {
nama: "Dina",
profilGambar: "https://via.placeholder.com/50", // Gambar profil pelapor
},
};
const PengaduanScreen = ({ navigation }) => {
return (
<View style={styles.container}>
{/* Tombol Kembali */}
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={28} color="#2D572C" />
</TouchableOpacity>
{/* Judul */}
<Text style={styles.title}>PENGADUAN</Text>
{/* Container Pengaduan */}
<ScrollView style={styles.pengaduanContainer}>
<View style={styles.pengaduanBox}>
<Text style={styles.pengaduanJudul}>{pengaduanData.judul}</Text>
<Text style={styles.pengaduanAlamat}>{pengaduanData.alamat}</Text>
<Text style={styles.pengaduanCatatan}>{pengaduanData.catatan}</Text>
<Text style={styles.pengaduanTanggal}>
Tanggal: {pengaduanData.tanggal}
</Text>
<Image
source={{ uri: pengaduanData.gambar }}
style={styles.buktiImage}
/>
{/* Profil Pelapor */}
<View style={styles.pelaporContainer}>
<Image
source={{ uri: pengaduanData.pelapor.profilGambar }}
style={styles.pelaporImage}
/>
<Text style={styles.pelaporNama}>{pengaduanData.pelapor.nama}</Text>
</View>
{/* Status Pengaduan */}
<View style={styles.statusContainer}>
<Text style={styles.statusText}>{pengaduanData.status}</Text>
{/* Jika Status Sedang Diproses */}
{pengaduanData.status === "Sedang Diproses" && (
<TouchableOpacity style={styles.kontribusiButton}>
<Text style={styles.kontribusiText}>Kontribusi</Text>
</TouchableOpacity>
)}
{/* Jika Status Sedang Diproses */}
{pengaduanData.status === "Sedang Diproses" && (
<Text style={styles.koinText}>Dapatkan Koin 300</Text>
)}
</View>
</View>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: "#fff",
},
backButton: {
marginBottom: 16,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#2D572C",
marginBottom: 20,
textAlign: "center",
},
pengaduanContainer: {
flex: 1,
},
pengaduanBox: {
padding: 16,
backgroundColor: "#F8F8F8",
borderRadius: 8,
marginBottom: 20,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 5,
elevation: 3,
},
pengaduanJudul: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
pengaduanAlamat: {
marginTop: 8,
fontSize: 14,
color: "#555",
},
pengaduanCatatan: {
marginTop: 8,
fontSize: 14,
color: "#555",
},
pengaduanTanggal: {
marginTop: 8,
fontSize: 14,
color: "#777",
},
buktiImage: {
marginTop: 16,
width: "100%",
height: 150,
borderRadius: 8,
},
pelaporContainer: {
flexDirection: "row",
alignItems: "center",
marginTop: 16,
},
pelaporImage: {
width: 40,
height: 40,
borderRadius: 20,
},
pelaporNama: {
marginLeft: 12,
fontSize: 14,
fontWeight: "bold",
color: "#333",
},
statusContainer: {
marginTop: 16,
alignItems: "center",
},
statusText: {
fontSize: 16,
fontWeight: "bold",
color: "#FF6F61", // Bisa diganti dengan warna yang sesuai status
},
kontribusiButton: {
marginTop: 12,
backgroundColor: "#2D572C",
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 8,
},
kontribusiText: {
color: "#fff",
fontWeight: "bold",
},
koinText: {
marginTop: 8,
fontSize: 12,
color: "#555",
},
});
export default PengaduanScreen;

View File

@ -0,0 +1,215 @@
import React from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
const pengaduanData = {
id: 1,
judul: "Sampah Menumpuk di Jalan Raya",
alamat: "Jl. Raya No. 25, Desa Suka Maju, Nganjuk",
catatan: "Mohon segera dibersihkan, sudah terlalu lama menumpuk.",
tanggal: "2025-04-28",
status: "Sedang Diproses", // Bisa diganti dengan 'Sedang Diverifikasi', 'Ditolak', dll.
pelapor: {
nama: "Dina",
profilGambar:
"https://imgv3.fotor.com/images/gallery/a-woman-linkedin-picture-with-grey-background-made-by-LinkedIn-Profile-Picture-Maker.jpg", // Gambar profil pelapor
},
gambarSampah: [
"https://majanews.com/wp-content/uploads/2022/07/0_20220718_193954.jpg", // Image 1
"https://newvision-media.s3.amazonaws.com/cms/d2d008c8-1703-4c3e-8b34-3181fc5eda5d.jpg", // Image 2// Image 3
// "https://newvision-media.s3.amazonaws.com/cms/d2d008c8-1703-4c3e-8b34-3181fc5eda5d.jpg", // Image 2// Image 3
// "https://newvision-media.s3.amazonaws.com/cms/d2d008c8-1703-4c3e-8b34-3181fc5eda5d.jpg", // Image 2// Image 3
"https://newvision-media.s3.amazonaws.com/cms/d2d008c8-1703-4c3e-8b34-3181fc5eda5d.jpg", // Image 2// Image 3
],
};
const PengaduanScreen = ({ navigation }) => {
return (
<View style={styles.container}>
{/* Judul Pengaduan */}
<Text style={styles.title}>PENGADUAN</Text>
{/* Tombol Kembali */}
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={28} color="#2D572C" />
</TouchableOpacity>
{/* Container Pengaduan */}
<ScrollView style={styles.pengaduanContainer}>
<View style={styles.pelaporContainer}>
<Image
source={{ uri: pengaduanData.pelapor.profilGambar }}
style={styles.pelaporImage}
/>
<Text style={styles.pelaporNama}>{pengaduanData.pelapor.nama}</Text>
</View>
<View style={styles.pengaduanBox}>
<Text style={styles.pengaduanJudul}>{pengaduanData.judul}</Text>
<Text style={styles.pengaduanAlamat}>{pengaduanData.alamat}</Text>
<Text style={styles.pengaduanCatatan}>{pengaduanData.catatan}</Text>
<Text style={styles.pengaduanTanggal}>
Tanggal: {pengaduanData.tanggal}
</Text>
{/* Gambar Sampah - Row Layout */}
<View style={styles.rowContainer}>
{pengaduanData.gambarSampah.map((image, index) => (
<Image
key={index}
source={{ uri: image }}
style={styles.sampahImage}
/>
))}
</View>
{/* Profil Pelapor */}
{/* Status Pengaduan */}
<View style={styles.statusContainer}>
<TouchableOpacity style={styles.kontribusiButton}>
<Text style={styles.kontribusiText}>Kontribusi</Text>
</TouchableOpacity>
{/* Jika Status Sedang Diproses */}
{pengaduanData.status === "Sedang Diproses" && (
<Text style={styles.koinText}>Dapatkan Koin 300</Text>
)}
</View>
</View>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: "#fff",
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#000",
marginBottom: 16,
marginTop: 16, // Reduced margin to bring title closer
textAlign: "left",
marginLeft: 35,
},
backButton: {
marginBottom: 20,
marginTop: 10, // Space between back button and title
position: "absolute", // Positioning it at the top-left
top: 20,
left: 10,
zIndex: 1,
},
pengaduanContainer: {
flex: 1,
},
pengaduanBox: {
padding: 16,
backgroundColor: "#fff",
borderRadius: 8,
marginBottom: 20,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 5,
elevation: 3,
marginTop: 20,
},
pengaduanJudul: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
pengaduanAlamat: {
marginTop: 8,
fontSize: 14,
color: "#555",
},
pengaduanCatatan: {
marginTop: 8,
fontSize: 14,
color: "#555",
},
pengaduanTanggal: {
marginTop: 8,
fontSize: 14,
color: "#777",
},
buktiImage: {
marginTop: 16,
width: "100%",
height: 150,
borderRadius: 8,
},
rowContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginTop: 26,
marginTop: 16,
width: "70%",
height: 80,
borderRadius: 8,
},
sampahImage: {
width: 80,
height: 80,
borderRadius: 8,
},
pelaporContainer: {
flexDirection: "row",
alignItems: "center",
marginTop: 16,
marginLeft: 20,
},
pelaporImage: {
width: 50,
height: 50,
borderRadius: 20,
},
pelaporNama: {
marginLeft: 12,
fontSize: 14,
fontWeight: "bold",
color: "#333",
},
statusContainer: {
marginTop: 16,
alignItems: "center",
},
statusText: {
fontSize: 16,
fontWeight: "bold",
color: "#FF6F61", // Bisa diganti dengan warna yang sesuai status
},
kontribusiButton: {
marginTop: 12,
backgroundColor: "#2D572C",
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 8,
},
kontribusiText: {
color: "#fff",
fontWeight: "bold",
},
koinText: {
marginTop: 8,
fontSize: 12,
color: "#555",
},
});
export default PengaduanScreen;

View File

@ -0,0 +1,80 @@
import React from "react";
import { View, Text, Button, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons"; // Menggunakan ikon ceklis
const KontribusiBerhasil = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={styles.content}>
<MaterialCommunityIcons name="cloud-check" size={140} color="white" />
<Text style={styles.title}>Kontribusi Berhasil !</Text>
{/* <Text style={styles.message}>
Mohon pastikan informasi yang diberikan sudah sesuai, agar kami dapat
segera menindaklanjuti.
</Text> */}
<Text style={styles.subMessage}>
Terima kasih telah berkontribusi untuk lingkungan!
</Text>
<TouchableOpacity
style={styles.button}
// onPress={() => console.log("Daftar Submit")}
onPress={() => navigation.navigate("BerandaPengaduan")}
>
<Text style={styles.buttonText}>LIHAT KONTRIBUSI</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap
},
content: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk efek overlay
padding: 30,
borderRadius: 15,
width: "80%",
alignItems: "center",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#ffea00",
marginTop: 0,
},
message: {
fontSize: 16,
color: "#fff",
textAlign: "center",
marginTop: 10,
},
subMessage: {
fontSize: 15,
color: "#ffea00",
textAlign: "center",
marginTop: 10,
padding: 3,
},
button: {
backgroundColor: "#fff",
paddingVertical: 10,
paddingHorizontal: 40,
borderRadius: 5,
marginTop: 20,
borderRadius: 25,
fontWeight: "bold",
},
buttonText: {
fontWeight: "bold",
fontSize: 15,
},
});
export default KontribusiBerhasil;

View File

@ -0,0 +1,280 @@
import React, { useState, useEffect } from "react";
import {
ScrollView,
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
Alert,
Image,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Icon library for the media buttons
import * as ImagePicker from "expo-image-picker"; // For picking images
import * as MediaLibrary from "expo-media-library"; // For accessing media library
import { Video } from "expo-av"; // For displaying videos
const KontribusiScreen = ({ navigation, route }) => {
const {
judulPengaduan = "Sampah berantakan",
tempatPengaduan = "Jl Raya Madiun Nganjuk",
} = route?.params || {};
const [catatan, setCatatan] = useState("");
const [photo, setPhoto] = useState(null);
const [video, setVideo] = useState(null);
// Request permissions for camera and media library
useEffect(() => {
const requestPermissions = async () => {
// Request permission for media library (Images and Videos)
const { status: mediaStatus } =
await ImagePicker.requestMediaLibraryPermissionsAsync();
if (mediaStatus !== "granted") {
Alert.alert(
"Permission required",
"You need to grant permission to access your media library."
);
}
// Optionally, you can also request permission for camera
const { status: cameraStatus } =
await ImagePicker.requestCameraPermissionsAsync();
if (cameraStatus !== "granted") {
Alert.alert(
"Permission required",
"You need to grant permission to use the camera."
);
}
};
requestPermissions();
}, []);
// Function to pick image
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
setPhoto(result.assets[0].uri); // Set the selected photo URI
} else {
Alert.alert("Tambah foto dibatalkan.");
}
};
// Function to pick video
const pickVideo = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Videos,
allowsEditing: true,
quality: 1,
});
if (!result.canceled) {
setVideo(result.assets[0].uri); // Set the selected video URI
} else {
Alert.alert("Pemilihan video dibatalkan.");
}
};
return (
<ScrollView style={styles.container}>
{/* Title and Back Button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>KONTRIBUSI SEKARANG</Text>
</View>
{/* Contribution Info Container */}
<View style={styles.contributionContainer}>
<View style={styles.infoBox}>
<Text style={styles.infoText1}>{judulPengaduan}</Text>
<Text style={styles.infoText2}>{tempatPengaduan}</Text>
</View>
{/* Add Media Row (Foto & Video) */}
<View style={styles.mediaRow}>
<TouchableOpacity style={styles.mediaButton} onPress={pickImage}>
<Ionicons name="image-outline" size={30} color="#2D572C" />
<Text style={styles.mediaButtonText}>Tambah Foto</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.mediaButton} onPress={pickVideo}>
<Ionicons name="videocam-outline" size={30} color="#2D572C" />
<Text style={styles.mediaButtonText}>Tambah Video</Text>
</TouchableOpacity>
</View>
{/* Display selected photo */}
{photo && (
<Image source={{ uri: photo }} style={styles.mediaThumbnail} />
)}
{/* Display selected video */}
{video && (
<Video
source={{ uri: video }}
style={styles.mediaThumbnail}
useNativeControls
resizeMode="contain"
isLooping
/>
)}
{/* Catatan (Note Input) */}
<TextInput
style={styles.input}
placeholder="Catatan"
multiline
value={catatan}
onChangeText={setCatatan}
/>
</View>
{/* Koin Message */}
<Text style={styles.koinText}>Dapatkan +520 Koin</Text>
{/* Post Button at Bottom */}
<TouchableOpacity
style={styles.postButton}
onPress={() => navigation.navigate("KontribusiBerhasil")}
>
<Text style={styles.postButtonText}>Posting</Text>
</TouchableOpacity>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f9f9f9",
},
header: {
flexDirection: "row",
alignItems: "center",
padding: 15,
backgroundColor: "#fff",
borderBottomLeftRadius: 20,
borderBottomRightRadius: 20,
},
backButton: {
marginRight: 15,
marginTop: 40,
},
title: {
fontSize: 22,
color: "#000",
fontWeight: "bold",
flex: 1,
textAlign: "left",
marginTop: 40,
},
contributionContainer: {
padding: 20,
backgroundColor: "#fff",
marginBottom: 20,
borderRadius: 12,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 4 },
shadowRadius: 4,
},
infoBox: {
marginBottom: 20,
},
infoText1: {
fontSize: 22,
color: "#333",
fontWeight: "700",
marginBottom: 5,
},
infoText2: {
fontSize: 18,
color: "#777",
fontWeight: "400",
},
mediaRow: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 25,
},
mediaButton: {
alignItems: "center",
flex: 1,
padding: 15,
backgroundColor: "#E8F5E9",
borderRadius: 10,
marginHorizontal: 10,
borderWidth: 1,
borderColor: "#2D572C",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 3 },
shadowRadius: 5,
elevation: 3,
},
mediaButtonText: {
fontSize: 14,
color: "#2D572C",
marginTop: 5,
},
input: {
height: 100,
borderColor: "#2D572C",
borderWidth: 1,
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 15,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 5,
elevation: 2,
},
koinText: {
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
color: "#2D572C",
marginBottom: 20,
},
postButton: {
backgroundColor: "#2D572C",
paddingVertical: 15,
borderRadius: 10,
marginBottom: 20,
alignItems: "center",
width: "90%",
alignSelf: "center",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 5 },
shadowRadius: 8,
elevation: 5,
},
postButtonText: {
fontSize: 18,
color: "#fff",
fontWeight: "bold",
},
mediaThumbnail: {
width: 300, // Adjust size for visibility
height: 200, // Adjust size for visibility
marginVertical: 10,
borderRadius: 8,
backgroundColor: "#f0f0f0",
},
});
export default KontribusiScreen;

View File

@ -0,0 +1,48 @@
import React, { useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator } from "react-native";
import { useNavigation } from "@react-navigation/native";
const LoadingKontribusi = () => {
const navigation = useNavigation();
// Menunggu selama 2 detik dan kemudian pindah ke halaman Home
useEffect(() => {
const timer = setTimeout(() => {
navigation.replace("KontribusiBerhasil"); // Ganti 'Home' dengan nama screen tujuan
}, 2000);
return () => clearTimeout(timer); // Membersihkan timer saat komponen dihapus
}, [navigation]);
return (
<View style={styles.container}>
<View style={styles.overlay}>
<ActivityIndicator size="large" color="#fff" />
<Text style={styles.loadingText}>Tunggu sebentar...</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap sebagai latar belakang
},
overlay: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk overlay
padding: 20,
borderRadius: 10,
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: "#fff",
},
});
export default LoadingKontribusi;

View File

@ -0,0 +1,50 @@
import React, { useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator } from "react-native";
import { useNavigation } from "@react-navigation/native";
const LoadingScreen = () => {
const navigation = useNavigation();
// Menunggu selama 2 detik dan kemudian pindah ke halaman Home
useEffect(() => {
const timer = setTimeout(() => {
navigation.replace("PengaduanWargaNavigator", {
screen: "PengaduanBerhasil",
}); // Ganti 'Home' dengan nama screen tujuan
}, 2000);
return () => clearTimeout(timer); // Membersihkan timer saat komponen dihapus
}, [navigation]);
return (
<View style={styles.container}>
<View style={styles.overlay}>
<ActivityIndicator size="large" color="#fff" />
<Text style={styles.loadingText}>Tunggu sebentar...</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap sebagai latar belakang
},
overlay: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk overlay
padding: 20,
borderRadius: 10,
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: "#fff",
},
});
export default LoadingScreen;

View File

@ -0,0 +1,80 @@
import React from "react";
import { View, Text, Button, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons"; // Menggunakan ikon ceklis
const PengaduanBerhasil = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={styles.content}>
<MaterialCommunityIcons name="cloud-check" size={140} color="white" />
<Text style={styles.title}>PENGADUAN BERHASIL !</Text>
<Text style={styles.message}>
Mohon pastikan informasi yang diberikan sudah sesuai, agar kami dapat
segera menindaklanjuti.
</Text>
<Text style={styles.subMessage}>
Laporan anda telah diterima dan sedang menunggu verifikasi
</Text>
<TouchableOpacity
style={styles.button}
// onPress={() => console.log("Daftar Submit")}
onPress={() => navigation.navigate("BerandaPengaduan")}
>
<Text style={styles.buttonText}>LIHAT PENGADUAN</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Warna hijau gelap
},
content: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#435739", // Transparansi gelap untuk efek overlay
padding: 30,
borderRadius: 15,
width: "80%",
alignItems: "center",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#ffea00",
marginTop: 0,
},
message: {
fontSize: 16,
color: "#fff",
textAlign: "center",
marginTop: 10,
},
subMessage: {
fontSize: 14,
color: "#ffea00",
textAlign: "center",
marginTop: 10,
padding: 3,
},
button: {
backgroundColor: "#fff",
paddingVertical: 10,
paddingHorizontal: 50,
borderRadius: 5,
marginTop: 20,
borderRadius: 25,
fontWeight: "bold",
},
buttonText: {
fontWeight: "bold",
fontSize: 15,
},
});
export default PengaduanBerhasil;

View File

@ -0,0 +1,284 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
ScrollView,
StyleSheet,
Image,
FlatList,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import * as Location from "expo-location";
import * as ImagePicker from "expo-image-picker";
import { Picker } from "@react-native-picker/picker"; // Import Picker
const desaOptions = ["Cangkringan", "Bogo", "Pesukidul", "Grojogan"];
const kecamatanOptions = ["Nganjuk", "Bagor", "Berbek", "Pace", "Wilangan"];
export default function PengaduanSampah() {
const navigation = useNavigation();
const [form, setForm] = useState({
nama: "",
noHp: "",
tanggal: "",
kategori: "",
namaJalan: "",
desa: "",
kecamatan: "",
tempat: "",
catatan: "",
});
const [imageUris, setImageUris] = useState([]); // Using array for multiple images
const [location, setLocation] = useState(null);
const [filteredDesa, setFilteredDesa] = useState(desaOptions);
const handleInputChange = (key, value) => {
setForm({ ...form, [key]: value });
};
// Filter desa based on input
const handleDesaSearch = (text) => {
setForm({ ...form, desa: text });
setFilteredDesa(
desaOptions.filter((desa) =>
desa.toLowerCase().includes(text.toLowerCase())
)
);
};
const getCurrentLocation = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
alert("Izin lokasi ditolak");
return;
}
try {
// Get user location
const loc = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.High,
});
setLocation(loc.coords);
// Geocoding API
const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${loc.coords.latitude},${loc.coords.longitude}&key=YOUR_GOOGLE_MAPS_API_KEY`;
const response = await fetch(geocodeUrl);
const data = await response.json();
if (data.status === "OK" && data.results.length > 0) {
const address = data.results[0].address_components;
const street =
address.find((component) => component.types.includes("route"))
?.long_name || "";
const village =
address.find((component) => component.types.includes("locality"))
?.long_name || "";
const place =
address.find((component) => component.types.includes("neighborhood"))
?.long_name || "";
setForm((prevForm) => ({
...prevForm,
namaJalan: street,
desa: village,
tempat: place,
}));
} else {
alert("Tidak dapat menemukan alamat untuk lokasi ini.");
}
} catch (error) {
console.error("Error getting address or location:", error);
alert("Terjadi kesalahan saat mengambil alamat atau lokasi.");
}
};
const pickImage = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
return;
}
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 1,
});
if (!result.canceled && result.assets.length > 0) {
// Add new image URI to the imageUris array
setImageUris((prevImages) => [...prevImages, result.assets[0].uri]);
}
};
const handleSubmit = () => {
// Cek semua field
if (!form.nama || !form.noHp || !form.tempat) {
alert("Harap lengkapi semua informasi yang diperlukan!");
return;
}
// validasi
console.log("Data Laporan:", { ...form, imageUris, location });
// alert("Laporan berhasil dikirim!");
navigation.navigate("PengaduanBerhasil");
};
return (
<ScrollView contentContainerStyle={styles.container}>
{/* Back Button */}
<TouchableOpacity
onPress={() => navigation.goBack()}
style={styles.backButton}
>
<Ionicons name="arrow-back" size={24} color="#000" />
</TouchableOpacity>
<Text style={styles.title}>PENGADUAN SAMPAH</Text>
<TextInput
style={styles.input}
placeholder="Nama Warga (Contoh: Johan Okta)"
value={form.nama}
onChangeText={(text) => handleInputChange("nama", text)}
/>
<TextInput
style={styles.input}
placeholder="No. HP Warga (Contoh: 081234567890)"
keyboardType="phone-pad"
value={form.noHp}
onChangeText={(text) => handleInputChange("noHp", text)}
/>
<Text style={styles.section}>LOKASI KEJADIAN</Text>
{/* Kecamatan Dropdown */}
<Text style={styles.inputLabel}>Kecamatan</Text>
<Picker
selectedValue={form.kecamatan}
onValueChange={(itemValue) => handleInputChange("kecamatan", itemValue)}
style={styles.input}
>
{kecamatanOptions.map((kecamatan, index) => (
<Picker.Item key={index} label={kecamatan} value={kecamatan} />
))}
</Picker>
<TextInput
style={styles.input}
placeholder="Tempat Kejadian (Contoh: Desa Cangkringan gang 4, Depan Toko)"
value={form.tempat}
onChangeText={(text) => handleInputChange("tempat", text)}
/>
<TextInput
style={[styles.input, { height: 100 }]}
multiline
placeholder="Catatan"
value={form.catatan}
onChangeText={(text) => handleInputChange("catatan", text)}
/>
<Text style={styles.section}>BUKTI PENDUKUNG</Text>
<View style={styles.row}>
<TouchableOpacity style={styles.buttonUpload} onPress={pickImage}>
<Text style={styles.buttonText}>Unggah</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.buttonUpload}
onPress={getCurrentLocation}
>
<Text style={styles.buttonText}>Lokasi Saat Ini</Text>
</TouchableOpacity>
</View>
{/* Display uploaded images */}
<ScrollView horizontal style={styles.imageGallery}>
{imageUris.map((uri, index) => (
<Image key={index} source={{ uri }} style={styles.imagePreview} />
))}
</ScrollView>
<TouchableOpacity style={styles.submitButton} onPress={handleSubmit}>
<Text style={styles.submitText}>LAPORKAN</Text>
</TouchableOpacity>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flexGrow: 1,
padding: 30,
backgroundColor: "#fff",
paddingTop: 20,
marginTop: 40,
},
backButton: {
position: "absolute",
top: 20,
left: 20,
zIndex: 10,
},
title: {
fontWeight: "bold",
fontSize: 22,
marginBottom: 20,
color: "#000",
textAlign: "left",
marginLeft: 25,
},
section: {
marginTop: 20,
fontWeight: "600",
marginBottom: 10,
color: "#444",
},
input: {
borderWidth: 1,
borderColor: "#aaa",
padding: 10,
borderRadius: 8,
marginBottom: 15,
},
inputLabel: {
fontWeight: "600",
marginBottom: 5,
},
row: {
flexDirection: "row",
justifyContent: "space-between",
},
buttonUpload: {
backgroundColor: "#ccc",
padding: 10,
borderRadius: 8,
flex: 1,
marginRight: 10,
},
buttonText: {
textAlign: "center",
},
imagePreview: {
marginTop: 10,
width: 100,
height: 100,
borderRadius: 10,
marginRight: 10,
},
imageGallery: {
flexDirection: "row",
marginTop: 10,
marginBottom: 20,
},
submitButton: {
marginTop: 30,
backgroundColor: "#2f4f2f",
padding: 15,
borderRadius: 10,
},
submitText: {
color: "#fff",
textAlign: "center",
fontWeight: "bold",
},
});

View File

@ -0,0 +1,230 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ScrollView,
} from "react-native";
import { Ionicons } from "@expo/vector-icons"; // Importing icons
const Donasi = ({ navigation }) => {
const [donationAmount, setDonationAmount] = useState("");
const [selectedGoal, setSelectedGoal] = useState(null);
const [description, setDescription] = useState("");
// Format donation input with thousands separator
const formatAmount = (amount) => {
return amount
.replace(/[^\d]/g, "") // Remove non-numeric characters
.replace(/\B(?=(\d{3})+(?!\d))/g, "."); // Add period as thousand separator
};
const handleDonationAmountChange = (value) => {
const formattedValue = formatAmount(value);
setDonationAmount(formattedValue);
};
// Handle Goal Selection
const handleGoalSelection = (goal) => {
setSelectedGoal(goal);
};
// Check if all fields are filled
const isFormValid = () => {
return donationAmount && selectedGoal && description.trim() !== "";
};
return (
<ScrollView style={styles.container}>
{/* Header with Back Button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>DONASI</Text>
</View>
{/* Donation Amount Input */}
<View style={styles.inputSection}>
<Text style={styles.inputLabel}>Jumlah Donasi</Text>
<View style={styles.donationInputContainer}>
<Text style={styles.rpLabel}>Rp.</Text>
<TextInput
style={styles.donationInput}
placeholder="Masukkan jumlah donasi"
placeholderTextColor="#888" // Gray placeholder text color
keyboardType="numeric"
value={donationAmount}
onChangeText={handleDonationAmountChange}
/>
</View>
</View>
{/* Donation Goal Selection */}
<View style={styles.goalsSection}>
<Text style={styles.inputLabel}>Tujuan Donasi</Text>
<View style={styles.goalsContainer}>
{[
"Pengelolaan Sampah",
"Program Penghijauan",
"Edukasi Lingkungan",
"Fasilitas Ramah Lingkungan",
"Kegiatan Pembersihan Lingkungan",
].map((goal) => (
<TouchableOpacity
key={goal}
style={[
styles.goalButton,
selectedGoal === goal && styles.selectedGoalButton,
]}
onPress={() => handleGoalSelection(goal)}
>
<Text
style={
selectedGoal === goal
? styles.selectedGoalText
: styles.goalText
}
>
{goal}
</Text>
</TouchableOpacity>
))}
</View>
</View>
{/* Description Input */}
<View style={styles.inputSection}>
<Text style={styles.inputLabel}>Deskripsi</Text>
<TextInput
style={styles.descriptionInput}
placeholder="Tuliskan deskripsi (opsional)"
multiline
numberOfLines={4}
value={description}
onChangeText={setDescription}
/>
</View>
{/* Next Button */}
<TouchableOpacity
style={[styles.nextButton, !isFormValid() && styles.disabledButton]}
onPress={() => isFormValid() && navigation.navigate("MetodeDonasi")}
disabled={!isFormValid()} // Disable if form is not valid
>
<Text style={styles.nextButtonText}>Selanjutnya</Text>
</TouchableOpacity>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: "#f9f9f9",
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 20,
marginTop: 30,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
},
inputSection: {
marginBottom: 20,
},
inputLabel: {
fontSize: 16,
color: "#333",
marginBottom: 8,
},
donationInputContainer: {
flexDirection: "row",
alignItems: "center",
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 8,
paddingLeft: 15,
backgroundColor: "#fff",
},
rpLabel: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
marginRight: 10,
},
donationInput: {
height: 50,
flex: 1,
fontSize: 18,
fontWeight: "bold",
backgroundColor: "#fff",
},
goalsSection: {
marginBottom: 20,
},
goalsContainer: {
flexDirection: "row",
flexWrap: "wrap",
gap: 10,
},
goalButton: {
borderWidth: 1,
borderColor: "#ddd",
paddingVertical: 8,
paddingHorizontal: 12,
borderRadius: 5,
backgroundColor: "#f0f0f0",
},
selectedGoalButton: {
borderColor: "#2D572C",
backgroundColor: "#e0f7e0",
},
goalText: {
fontSize: 14,
color: "#333",
},
selectedGoalText: {
fontSize: 14,
color: "#2D572C",
},
descriptionInput: {
height: 100,
borderColor: "#ddd",
borderWidth: 1,
borderRadius: 8,
paddingLeft: 15,
paddingTop: 10,
fontSize: 14,
backgroundColor: "#fff",
},
nextButton: {
backgroundColor: "#2D572C",
paddingVertical: 15,
borderRadius: 8,
alignItems: "center",
},
disabledButton: {
backgroundColor: "#b0b0b0", // Disabled button color
},
nextButtonText: {
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
});
export default Donasi;

View File

@ -0,0 +1,107 @@
import React, { useState } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
const DonasiVerifikasi = () => {
const navigation = useNavigation();
const [pin, setPin] = useState("");
const handlePinSubmit = () => {
if (pin.length === 6) {
alert("Pembayaran Tervalidasi");
} else {
alert("PIN harus 6 digit");
}
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => navigation.goBack()}
>
<Ionicons name="arrow-back" size={24} color="#333" />
</TouchableOpacity>
<Text style={styles.title}>VERIFIKASI PIN</Text>
</View>
<Text style={styles.instructionText}>
Masukkan PIN Anda untuk melanjutkan pembayaran
</Text>
<TextInput
style={styles.pinInput}
secureTextEntry
keyboardType="numeric"
maxLength={6}
placeholder="Masukkan PIN"
value={pin}
onChangeText={setPin}
/>
<TouchableOpacity
style={styles.submitButton}
// onPress={handlePinSubmit}
onPress={() => navigation.navigate("Donasiberhasil")}
>
<Text style={styles.submitButtonText}>Konfirmasi PIN</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: "#f9f9f9",
},
header: {
flexDirection: "row",
alignItems: "center",
marginBottom: 30,
marginTop: 30,
},
backButton: {
marginRight: 10,
},
title: {
fontSize: 22,
fontWeight: "bold",
color: "#333",
},
instructionText: {
fontSize: 16,
color: "#666",
marginVertical: 15,
},
pinInput: {
borderBottomWidth: 2,
borderColor: "#333",
fontSize: 20,
paddingVertical: 10,
textAlign: "center",
marginVertical: 20,
},
submitButton: {
backgroundColor: "#2D572C",
paddingVertical: 15,
borderRadius: 8,
alignItems: "center",
},
submitButtonText: {
color: "#fff",
fontSize: 16,
fontWeight: "bold",
},
});
export default DonasiVerifikasi;

View File

@ -0,0 +1,162 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialIcons } from "@expo/vector-icons";
const Donasiberhasil = ({ navigation }) => {
const currentDate = new Date().toLocaleDateString("id-ID", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
});
const donationAmount = 100000;
const paymentMethod = "Transfer DANA";
const description = "Pengelolaan Sampah";
const senderName = "Dina Dwi Anisa";
const accountName = "Dinas Lingkungan Hidup";
const transactionId = "DN230512XYZ";
return (
<View style={styles.container}>
<View style={styles.card}>
<MaterialIcons name="check-circle" size={70} color="#2D572C" />
<Text style={styles.successText}>Terima Kasih!</Text>
<Text style={styles.subText}>Donasi Anda Telah Berhasil</Text>
<View style={styles.separator} />
{/* Struk Donasi */}
<View style={styles.row}>
<Text style={styles.label}>Tanggal</Text>
<Text style={styles.value}>{currentDate}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>ID Transaksi</Text>
<Text style={styles.value}>{transactionId}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Nama Pengirim</Text>
<Text style={styles.value}>{senderName}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Akun Tujuan</Text>
<Text style={styles.value}>{accountName}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Jumlah Donasi</Text>
<Text style={styles.amount}>
Rp {donationAmount.toLocaleString("id-ID")}
</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Tujuan Donasi</Text>
<Text style={styles.value}>{description}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Metode Pembayaran</Text>
<Text style={styles.value}>{paymentMethod}</Text>
</View>
<View style={styles.thankYou}>
<Text style={styles.thankText}>
Semoga kebaikan Anda membawa berkah bagi banyak orang. 💚
</Text>
</View>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate("Home")}
>
<Text style={styles.buttonText}>Kembali ke Beranda</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default Donasiberhasil;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#F2F2F2",
justifyContent: "center",
alignItems: "center",
padding: 20,
},
card: {
backgroundColor: "#fff",
width: "100%",
borderRadius: 16,
padding: 25,
alignItems: "center",
shadowColor: "#000",
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 5,
},
successText: {
fontSize: 24,
fontWeight: "bold",
color: "#2D572C",
marginTop: 10,
},
subText: {
fontSize: 16,
color: "#444",
marginTop: 5,
marginBottom: 15,
},
separator: {
height: 1,
width: "100%",
backgroundColor: "#ccc",
marginVertical: 20,
},
row: {
width: "100%",
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 12,
},
label: {
fontSize: 16,
color: "#333",
fontWeight: "500",
},
value: {
fontSize: 16,
color: "#666",
textAlign: "right",
flexShrink: 1,
marginLeft: 20,
},
amount: {
fontSize: 18,
fontWeight: "bold",
color: "#2D572C",
},
thankYou: {
marginTop: 25,
marginBottom: 20,
paddingHorizontal: 10,
},
thankText: {
textAlign: "center",
color: "#555",
fontSize: 14,
fontStyle: "italic",
},
button: {
backgroundColor: "#2D572C",
paddingVertical: 14,
paddingHorizontal: 30,
borderRadius: 10,
},
buttonText: {
color: "#fff",
fontSize: 16,
fontWeight: "600",
},
});

Some files were not shown because too many files have changed in this diff Show More