This commit is contained in:
Stef-00012 2025-01-23 07:53:14 +01:00
parent 3b187b4ce4
commit 990f8ae017
No known key found for this signature in database
GPG key ID: 28BE9A9E4EF0E6BF
8 changed files with 225 additions and 45 deletions

View file

@ -25,8 +25,9 @@ export default function Layout() {
/>
<SafeAreaView style={{ flex: 1 }}>
<Header/>
<Slot />
<Header>
<Slot />
</Header>
</SafeAreaView>
</ShareIntentProvider>
);

View file

@ -1,12 +1,25 @@
import type { APIRecentFiles, APISelfUser, APIUserStats } from "@/types/zipline";
import { getRecentFiles, getCurrentUser } from "@/functions/zipline/user";
import { Text, View, TextInput, Pressable } from "react-native";
import { Table, Row, Rows } from "react-native-table-component";
import { useShareIntentContext } from "expo-share-intent";
import { getUserStats } from "@/functions/zipline/stats";
import { useEffect, useState } from "react";
import * as db from "@/functions/database";
import { useRouter } from "expo-router";
import { styles } from "@/styles/home";
import bytes from "bytes";
import type {
APIRecentFiles,
APISelfUser,
APIUserStats,
} from "@/types/zipline";
import {
Text,
View,
TextInput,
Pressable,
ScrollView,
Image,
} from "react-native";
export default function Home() {
const router = useRouter();
@ -31,23 +44,8 @@ export default function Home() {
const [stats, setStats] = useState<APIUserStats | null>();
const [recentFiles, setRecentFiles] = useState<APIRecentFiles | null>();
const mainContainerStyles = user ? {
...styles.mainContainer
} : {
...styles.mainContainer,
marginTop: 0
};
useEffect(() => {
(async () => {
const user = await getCurrentUser();
const stats = await getUserStats();
const recentFiles = await getRecentFiles();
setUser(user);
setStats(stats);
setRecentFiles(recentFiles);
})();
handleLogin();
}, []);
async function handleLogin() {
@ -61,13 +59,126 @@ export default function Home() {
}
return (
<View style={mainContainerStyles}>
<View style={styles.mainContainer}>
{url && token ? (
<View style={{flex:1}}>
{user ? (
<View>
<Text style={{color: "#fff"}}>{user.username}</Text>
</View>
<View
style={{
flex: 1,
}}
>
{user && stats && recentFiles ? (
<ScrollView>
<View>
<Text style={styles.headerText}>Recent Files</Text>
<ScrollView horizontal style={styles.scrollView}>
{recentFiles.map((file) => (
<View key={file.id} style={styles.recentFileContainer}>
<Image
key={file.id}
// src={`${url}/raw${file.url}`}
source={{
uri: `${url}/raw${file.url}`,
}}
alt={file.originalName || file.name}
width={200}
height={200}
resizeMode="contain"
/>
</View>
))}
</ScrollView>
</View>
<View>
<Text style={styles.headerText}>Stats</Text>
<ScrollView
horizontal
style={{
...styles.scrollView,
...styles.statsContainer,
}}
>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>Files Uploaded:</Text>
<Text style={styles.statText}>{stats.filesUploaded}</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>Favorite Files:</Text>
<Text style={styles.statText}>{stats.favoriteFiles}</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>Storage Used:</Text>
<Text style={styles.statText}>
{bytes(stats.storageUsed, {
unitSeparator: " ",
})}
</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>
Average Storage Used:
</Text>
<Text style={styles.statText}>
{bytes(stats.avgStorageUsed, {
unitSeparator: " ",
})}
</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>File Views:</Text>
<Text style={styles.statText}>{stats.views}</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>
File Average Views:
</Text>
<Text style={styles.statText}>
{Math.round(stats.avgViews)}
</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>Links Created:</Text>
<Text style={styles.statText}>{stats.urlsCreated}</Text>
</View>
<View style={styles.statContainer}>
<Text style={styles.subHeaderText}>Total Link View:</Text>
<Text style={styles.statText}>{stats.urlViews}</Text>
</View>
</ScrollView>
</View>
<View>
<Text style={styles.headerText}>File Types</Text>
<View
style={{
...styles.scrollView,
...styles.fileTypesContainer,
}}
>
<Table>
<Row
data={["File Type", "Count"]}
widthArr={[250, 150]}
textStyle={styles.tableHeadText}
/>
<Rows
data={Object.entries(stats.sortTypeCount).sort(
(a, b) => b[1] - a[1],
)}
widthArr={[250, 150]}
textStyle={styles.tableText}
/>
</Table>
</View>
</View>
</ScrollView>
) : (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>

BIN
bun.lockb

Binary file not shown.

View file

@ -1,30 +1,36 @@
import { getCurrentUser, getCurrentUserAvatar } from "@/functions/zipline/user";
import { type PropsWithChildren, useEffect, useRef, useState } from "react";
import { Stack, IconButton } from "@react-native-material/core";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { View, Text, Pressable, Image } from "react-native";
import type { APISelfUser } from "@/types/zipline";
import { useEffect, useState } from "react";
import { styles } from "@/styles/header";
import type React from "react";
export default function Header() {
export default function Header({ children }: PropsWithChildren) {
const [avatar, setAvatar] = useState<string | null>(null);
const [user, setUser] = useState<APISelfUser | null>(null);
useEffect(() => {
(async () => {
const avatar = await getCurrentUserAvatar();
const user = await getCurrentUser();
setAvatar(avatar);
setUser(user);
})();
});
if (!avatar || !user) {
(async () => {
const avatar = await getCurrentUserAvatar();
const user = await getCurrentUser();
setAvatar(avatar);
setUser(user);
})();
}
}, [avatar, user]);
return (
<View>
<View style={styles.headerContainer}>
{avatar && user ? (
<View>
<View
style={{
marginBottom: 70
}}
>
<View style={styles.header}>
<View style={styles.headerLeft}>
<IconButton
@ -61,6 +67,7 @@ export default function Header() {
) : (
<View />
)}
{children}
</View>
);
}

View file

@ -3,7 +3,7 @@ import type { APIFile, APIFiles, APISettings } from "@/types/zipline";
import { getSettings } from "@/functions/zipline/settings";
import type { Mimetypes } from "@/types/mimetypes";
import * as db from "@/functions/database";
import bytesFn from "bytes";
import bytes from "bytes";
import axios from "axios";
// GET /api/user/files
@ -167,9 +167,9 @@ export async function uploadFile(
const settings = await getSettings();
const chunksMax = bytesFn(settings?.chunksMax || "95mb") || 95 * 1024 * 1024;
const chunksMax = bytes(settings?.chunksMax || "95mb") || 95 * 1024 * 1024;
const chunksSize =
bytesFn(settings?.chunksSize || "25mb") || 25 * 1024 * 1024;
bytes(settings?.chunksSize || "25mb") || 25 * 1024 * 1024;
const headers: {
[key: string]: string;

View file

@ -4,6 +4,7 @@
"version": "1.0.0",
"scripts": {
"start": "expo start",
"start:dev": "expo start --dev-client",
"prebuild": "expo prebuild --no-install --clean",
"run:android": "expo run:android",
"run:ios": "expo run:ios",
@ -45,6 +46,7 @@
"react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "~4.4.0",
"react-native-table-component": "^1.2.2",
"react-native-web": "~0.19.13",
"react-native-webview": "13.12.5"
},
@ -53,6 +55,7 @@
"@types/bytes": "^3.1.5",
"@types/jest": "^29.5.12",
"@types/react": "~18.3.12",
"@types/react-native-table-component": "^1.2.8",
"@types/react-test-renderer": "^18.3.0",
"jest": "^29.2.1",
"jest-expo": "~52.0.3",

View file

@ -1,6 +1,9 @@
import { StyleSheet } from "react-native";
export const styles = StyleSheet.create({
headerContainer: {
flex: 1
},
header: {
position: "absolute",
top: 0,
@ -39,6 +42,7 @@ export const styles = StyleSheet.create({
userMenuContainer: {
flexWrap: "wrap",
flexDirection: "row",
marginRight: 5
},
userMenuAvatar: {
borderRadius: 8

View file

@ -4,19 +4,18 @@ export const styles = StyleSheet.create({
mainContainer: {
backgroundColor: "#0c101c",
flex: 1,
marginTop: 50
},
loadingContainer: {
flex: 1,
display: "flex"
display: "flex",
flex: 1
},
loadingText: {
fontSize: 40,
fontWeight: "bold",
margin: "auto",
color: "#304270",
justifyContent: "center",
alignItems: "center",
color: "#304270",
},
loginContainer: {
display: "flex",
@ -55,5 +54,60 @@ export const styles = StyleSheet.create({
textAlign: "center",
fontWeight: "bold",
color: "white"
},
scrollView: {
marginTop: 15,
borderStyle: "solid",
borderWidth: 2,
borderColor: "#222c47",
marginHorizontal: 10,
borderRadius: 15,
padding: 15
},
recentFileContainer: {
marginHorizontal: 10,
},
statsContainer: {
paddingHorizontal: 7
},
headerText: {
marginTop: 5,
marginLeft: 10,
fontSize: 23,
fontWeight: "bold",
color: "white"
},
subHeaderText: {
fontSize: 18,
fontWeight: "bold",
color: "gray"
},
statText: {
marginTop: 5,
fontSize: 32,
fontWeight: "bold",
color: "white"
},
statContainer: {
borderWidth: 2,
borderColor: "#222c47",
borderStyle: "solid",
borderRadius: 10,
padding: 10,
marginHorizontal: 4
},
tableText: {
color: "white",
fontSize: 16,
marginHorizontal: 10
},
fileTypesContainer: {
marginBottom: 10,
},
tableHeadText: {
color: "white",
fontWeight: "bold",
fontSize: 16,
marginHorizontal: 10
}
});