mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
mobile: add user profile
This commit is contained in:
committed by
Abdullah Atta
parent
9e71c5e68a
commit
7f62262eaf
@@ -52,7 +52,7 @@ const ImagePreview = () => {
|
||||
setLoading(true);
|
||||
setTimeout(async () => {
|
||||
let hash = image.hash;
|
||||
if (!hash && dataurl.toObject(image.src)) {
|
||||
if (!hash && image.src && dataurl.toObject(image.src)) {
|
||||
const data = dataurl.toObject(image.src);
|
||||
if (!data) return;
|
||||
hash = await Sodium.hashFile({
|
||||
|
||||
@@ -46,6 +46,8 @@ export const UserStatus = () => {
|
||||
const { isInternetReachable } = useNetInfo();
|
||||
const isOffline = !isInternetReachable;
|
||||
const { progress } = useSyncProgress();
|
||||
const userProfile = useUserStore((state) => state.profile);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@@ -81,16 +83,15 @@ export const UserStatus = () => {
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{user ? (
|
||||
{userProfile?.profilePicture ? (
|
||||
<Image
|
||||
source={{
|
||||
uri: PROFILE_PIC_URL
|
||||
uri: userProfile?.profilePicture
|
||||
}}
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35,
|
||||
borderRadius: 100,
|
||||
backgroundColor: "red",
|
||||
marginRight: 10
|
||||
}}
|
||||
/>
|
||||
@@ -117,7 +118,9 @@ export const UserStatus = () => {
|
||||
? `Syncing your notes${
|
||||
progress ? ` (${progress.current})` : ""
|
||||
}`
|
||||
: "Ammar Ahmed"}
|
||||
: !userProfile?.fullName
|
||||
? "Tap to sync"
|
||||
: userProfile.fullName}
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph
|
||||
|
||||
@@ -389,6 +389,11 @@ export const useAppEvents = () => {
|
||||
|
||||
const isUserEmailConfirmed = SettingsService.get().userEmailConfirmed;
|
||||
setUser(user);
|
||||
|
||||
useUserStore.setState({
|
||||
profile: await db.user.getProfile()
|
||||
});
|
||||
|
||||
if (SettingsService.get().sessionExpired) {
|
||||
syncedOnLaunch.current = true;
|
||||
return;
|
||||
|
||||
@@ -70,7 +70,6 @@ import { useDragState } from "./editor/state";
|
||||
import { verifyUser, verifyUserWithApplock } from "./functions";
|
||||
import { SettingSection } from "./types";
|
||||
import { getTimeLeft } from "./user-section";
|
||||
import ImagePicker from "react-native-image-crop-picker";
|
||||
|
||||
type User = any;
|
||||
|
||||
@@ -135,49 +134,53 @@ export const settingsGroups: SettingSection[] = [
|
||||
description: "Manage account",
|
||||
sections: [
|
||||
{
|
||||
id: "change-profile-picture",
|
||||
name: "Change profile picture",
|
||||
description: "Change your profile picture",
|
||||
icon: "account-outline",
|
||||
id: "remove-profile-picture",
|
||||
name: "Remove profile picture",
|
||||
description: "Remove your picture from profile",
|
||||
useHook: () =>
|
||||
useUserStore((state) => state.profile?.profilePicture),
|
||||
hidden: () => !useUserStore.getState().profile?.profilePicture,
|
||||
modifer: () => {
|
||||
const theme =
|
||||
useThemeStore.getState().colorScheme === "dark"
|
||||
? useThemeStore.getState().darkTheme
|
||||
: useThemeStore.getState().lightTheme;
|
||||
ImagePicker.openPicker({
|
||||
compressImageMaxWidth: 512,
|
||||
compressImageMaxHeight: 512,
|
||||
compressImageQuality: 0.8,
|
||||
avoidEmptySpaceAroundImage: true,
|
||||
cropping: true,
|
||||
cropperCircleOverlay: true,
|
||||
mediaType: "photo",
|
||||
forceJpg: true,
|
||||
includeBase64: true,
|
||||
writeTempFile: false,
|
||||
cropperToolbarColor: theme.scopes.base.primary.background,
|
||||
cropperToolbarTitle: "Edit profile picture",
|
||||
cropperActiveWidgetColor: theme.scopes.base.primary.accent,
|
||||
cropperToolbarWidgetColor: theme.scopes.base.primary.icon
|
||||
}).then((image) => {
|
||||
console.log(image);
|
||||
presentDialog({
|
||||
title: "Remove profile picture",
|
||||
paragraph:
|
||||
"Are you sure you want to remove your profile picture?",
|
||||
positiveText: "Remove",
|
||||
positivePress: async () => {
|
||||
db.user
|
||||
.setProfile({
|
||||
profilePicture: undefined
|
||||
})
|
||||
.then(async () => {
|
||||
useUserStore.setState({
|
||||
profile: await db.user.getProfile()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "change-name",
|
||||
name: "Change name",
|
||||
description: "Change your name",
|
||||
id: "remove-name",
|
||||
name: "Remove full name",
|
||||
description: "Remove your name from profile",
|
||||
useHook: () => useUserStore((state) => state.profile?.fullName),
|
||||
hidden: () => !useUserStore.getState().profile?.fullName,
|
||||
modifer: () => {
|
||||
presentDialog({
|
||||
title: "Change name",
|
||||
paragraph: "Change your name",
|
||||
positiveText: "Save",
|
||||
input: true,
|
||||
inputPlaceholder: "Enter new name",
|
||||
defaultValue: "Ammar Ahmed",
|
||||
positivePress(value) {
|
||||
console.log(value);
|
||||
title: "Remove name",
|
||||
paragraph: "Are you sure you want to remove your name?",
|
||||
positiveText: "Remove",
|
||||
positivePress: async () => {
|
||||
db.user
|
||||
.setProfile({
|
||||
fullName: undefined
|
||||
})
|
||||
.then(async () => {
|
||||
useUserStore.setState({
|
||||
profile: await db.user.getProfile()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,22 +17,24 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useNetInfo } from "@react-native-community/netinfo";
|
||||
import dayjs from "dayjs";
|
||||
import React from "react";
|
||||
import { Image, View } from "react-native";
|
||||
import { Image, TouchableOpacity, View } from "react-native";
|
||||
import ImagePicker from "react-native-image-crop-picker";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../common/database";
|
||||
import { presentDialog } from "../../components/dialog/functions";
|
||||
import AppIcon from "../../components/ui/AppIcon";
|
||||
import { TimeSince } from "../../components/ui/time-since";
|
||||
import Heading from "../../components/ui/typography/heading";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { SyncStatus, useUserStore } from "../../stores/use-user-store";
|
||||
import { SUBSCRIPTION_STATUS_STRINGS } from "../../utils/constants";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { SectionItem } from "./section-item";
|
||||
import { useNetInfo } from "@react-native-community/netinfo";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
|
||||
const PROFILE_PIC_URL = `https://picsum.photos/id/177/367/267`;
|
||||
|
||||
export const getTimeLeft = (t2) => {
|
||||
let daysRemaining = dayjs(t2).diff(dayjs(), "days");
|
||||
@@ -45,28 +47,56 @@ export const getTimeLeft = (t2) => {
|
||||
const ProfilePicPlaceholder = () => {
|
||||
const { colors } = useThemeColors();
|
||||
return (
|
||||
<View
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center"
|
||||
}}
|
||||
activeOpacity={0.9}
|
||||
onPress={() => {
|
||||
const theme =
|
||||
useThemeStore.getState().colorScheme === "dark"
|
||||
? useThemeStore.getState().darkTheme
|
||||
: useThemeStore.getState().lightTheme;
|
||||
|
||||
ImagePicker.openPicker({
|
||||
compressImageMaxWidth: 256,
|
||||
compressImageMaxHeight: 256,
|
||||
compressImageQuality: 0.8,
|
||||
avoidEmptySpaceAroundImage: true,
|
||||
cropping: true,
|
||||
cropperCircleOverlay: true,
|
||||
mediaType: "photo",
|
||||
forceJpg: true,
|
||||
includeBase64: true,
|
||||
writeTempFile: false,
|
||||
cropperToolbarColor: theme.scopes.base.primary.background,
|
||||
cropperToolbarTitle: "Edit profile picture",
|
||||
cropperActiveWidgetColor: theme.scopes.base.primary.accent,
|
||||
cropperToolbarWidgetColor: theme.scopes.base.primary.icon
|
||||
}).then(async (image) => {
|
||||
if (!image.data) return;
|
||||
await db.user.setProfile({
|
||||
profilePicture: "data:image/jpeg;base64," + image.data
|
||||
});
|
||||
useUserStore.setState({
|
||||
profile: await db.user.getProfile()
|
||||
});
|
||||
});
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.primary.shade,
|
||||
borderRadius: 100,
|
||||
width: 50,
|
||||
height: 50,
|
||||
width: 100,
|
||||
height: 100,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
size={SIZE.xl}
|
||||
color={colors.primary.accent}
|
||||
name="account-outline"
|
||||
/>
|
||||
<Icon size={50} color={colors.primary.accent} name="account-outline" />
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -77,6 +107,7 @@ const SettingsUserSection = ({ item }) => {
|
||||
const lastSyncStatus = useUserStore((state) => state.lastSyncStatus);
|
||||
const { isInternetReachable } = useNetInfo();
|
||||
const isOffline = !isInternetReachable;
|
||||
const userProfile = useUserStore((state) => state.profile);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -98,8 +129,6 @@ const SettingsUserSection = ({ item }) => {
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
{/* <ProfilePicPlaceholder /> */}
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
@@ -115,17 +144,20 @@ const SettingsUserSection = ({ item }) => {
|
||||
borderColor: colors.primary.accent
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={{
|
||||
uri: PROFILE_PIC_URL
|
||||
}}
|
||||
style={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 100,
|
||||
backgroundColor: "red"
|
||||
}}
|
||||
/>
|
||||
{userProfile?.profilePicture ? (
|
||||
<Image
|
||||
source={{
|
||||
uri: userProfile?.profilePicture
|
||||
}}
|
||||
style={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 100
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ProfilePicPlaceholder />
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View
|
||||
@@ -139,8 +171,35 @@ const SettingsUserSection = ({ item }) => {
|
||||
]?.toUpperCase() || "Basic"}
|
||||
</Heading>
|
||||
|
||||
<Paragraph color={colors.primary.heading} size={SIZE.lg}>
|
||||
Ammar Ahmed
|
||||
<Paragraph
|
||||
onPress={() => {
|
||||
presentDialog({
|
||||
title: "Set name",
|
||||
paragraph: "Set your full name",
|
||||
positiveText: "Save",
|
||||
input: true,
|
||||
inputPlaceholder: "Enter your full name",
|
||||
defaultValue: userProfile?.fullName,
|
||||
positivePress: async (value) => {
|
||||
db.user
|
||||
.setProfile({
|
||||
fullName: value
|
||||
})
|
||||
.then(async () => {
|
||||
useUserStore.setState({
|
||||
profile: await db.user.getProfile()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
color={colors.primary.heading}
|
||||
size={SIZE.lg}
|
||||
>
|
||||
{userProfile?.fullName
|
||||
? userProfile.fullName + " "
|
||||
: "Set your name "}
|
||||
<AppIcon name="pencil" size={SIZE.lg} />
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph color={colors.primary.heading} size={SIZE.xs}>
|
||||
@@ -149,7 +208,8 @@ const SettingsUserSection = ({ item }) => {
|
||||
|
||||
<Paragraph
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
flexWrap: "wrap",
|
||||
marginTop: 5
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
color={colors.secondary.heading}
|
||||
@@ -188,8 +248,6 @@ const SettingsUserSection = ({ item }) => {
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<IconButton name="pencil" />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { User } from "@notesnook/core/dist/api/user-manager";
|
||||
import { Profile } from "@notesnook/core";
|
||||
import { User } from "@notesnook/core";
|
||||
import create, { State } from "zustand";
|
||||
|
||||
export enum SyncStatus {
|
||||
@@ -40,6 +41,7 @@ export interface UserStore extends State {
|
||||
lockApp: (verified: boolean) => void;
|
||||
disableAppLockRequests: boolean;
|
||||
setDisableAppLockRequests: (shouldBlockVerifyUser: boolean) => void;
|
||||
profile?: Partial<Profile>;
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserStore>((set) => ({
|
||||
@@ -62,5 +64,6 @@ export const useUserStore = create<UserStore>((set) => ({
|
||||
setTimeout(() => {
|
||||
set({ disableAppLockRequests: false });
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
profile: undefined
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user