master
Netcup Gituser 2023-12-16 09:38:51 +01:00
parent 91df8a53bb
commit 486ef51863
19 changed files with 424 additions and 88 deletions

View File

@ -4,7 +4,7 @@ import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
interface MyIconProps {
name: string;
size?: number | undefined;
color?: number | ColorValue | undefined
color?: number | ColorValue | undefined;
}
export function MyIcon({name, size, color}: MyIconProps) {

View File

@ -3,6 +3,11 @@ import {Image, ImageProps} from 'react-native';
type imageType = Blob | undefined;
export interface BasicImageProp {
source: SourceProp;
url?: string;
data?: imageType;
}
interface CustomImageProps extends ImageProps {
hq?: {source: SourceProp; data: imageType; url: string};
}
@ -11,4 +16,20 @@ function MyImage({...rest}: CustomImageProps) {
return <Image {...rest} />;
}
export function getImageURL(
image: (BasicImageProp | undefined)[],
): string | undefined {
for (let i = 0; i < image.length; i++) {
const img = image[i];
if (img === undefined) continue;
if (img.source === SourceProp.online) {
if (img.url !== undefined) return img.url;
}
}
return undefined;
}
export default MyImage;

View File

@ -2,12 +2,5 @@ import {Suspense} from 'react';
import {Text} from 'react-native';
export function MySuspenseFallback({children}: {children: React.ReactNode}) {
console.log('MySuspenseFallback');
return (
<Suspense
fallback={<Text style={{color: 'red', fontSize: 64}}>loading...</Text>}>
{children}
</Suspense>
);
return <Suspense fallback={<Text>loading...</Text>}>{children}</Suspense>;
}

View File

@ -4,10 +4,10 @@ import {appStatus, non_save_vars} from './appNonSaveVar';
import {ThemeTokensType} from '@configs/colors';
import {chatEntity, roomId} from '@configs/chat/types';
import {User} from '@user/types';
import {SourceProp, User} from '@user/types';
import {AccountName, EventId} from './types';
import {PA_Point} from '@components/map/types';
import {PAEvent} from '@event/types';
import {PAEvent, createEventProp} from '@event/types';
export const appNonSaveVariablesSlice = createSlice({
name: 'non_save_vars',
@ -31,7 +31,10 @@ export const appNonSaveVariablesSlice = createSlice({
removeCachedEvent: (state, action: PayloadAction<EventId>) => {
delete state.cachedEvents[action.payload];
},
setJoinedEvent: (state, action: PayloadAction<{id: EventId, isJoined: number}>) => {
state.cachedEvents[action.payload.id].isJoined = createEventProp(SourceProp.cached, action.payload.isJoined);
},
setSelectedChat: (state, action: PayloadAction<roomId>) => {
state.selectedChat = action.payload;
},

View File

@ -17,6 +17,8 @@ import {
} from './types';
import {SourceProp} from '@user/types';
import { appVarActions } from '@configs/appVarReducer';
import { get } from '@gluestack-style/react';
let cachedEventList: EventID[] = [];
@ -117,6 +119,12 @@ async function getEvent(
),
lastUpdateTimestamp: eve[eveDBKeys.lastUpdateTimestamp],
EventBannerPicture,
isJoined: createEventProp(SourceProp.offline, eve[eveDBKeys.isJoined]),
minAge: createEventProp(SourceProp.offline, eve[eveDBKeys.minAge]),
AddressText: createEventProp(
SourceProp.offline,
eve[eveDBKeys.AddressText],
),
};
}
}
@ -153,23 +161,10 @@ async function getEvent(
const resp = {
response: {
Name: 'test event',
Name: 'Bootshaus',
Description:
'das Event "Tech House Germany" am 08.12.2023 im legendären Bootshaus Köln verspricht eine unvergessliche Nacht voller elektrisierender Beats und pulsierender Rhythmen. Jeder DJ bringt seinen einzigartigen Stil und Energie in das Line-up ein, was eine perfekte Mischung aus klassischem und modernem Tech House garantiert. \n\n' +
'Das Bootshaus, bekannt für seine hervorragende Akustik und beeindruckende Lichtshow, bietet die perfekte Kulisse für eine Nacht voller Tanz und Musik. Erleben Sie eine Reise durch die Welt des Tech House, begleitet von den besten Künstlern der Szene. \n\n' +
'\n\n\n' +
'das Event "Tech House Germany" am 08.12.2023 im legendären Bootshaus Köln verspricht eine unvergessliche Nacht voller elektrisierender Beats und pulsierender Rhythmen. Jeder DJ bringt seinen einzigartigen Stil und Energie in das Line-up ein, was eine perfekte Mischung aus klassischem und modernem Tech House garantiert. \n\n' +
'Das Bootshaus, bekannt für seine hervorragende Akustik und beeindruckende Lichtshow, bietet die perfekte Kulisse für eine Nacht voller Tanz und Musik. Erleben Sie eine Reise durch die Welt des Tech House, begleitet von den besten Künstlern der Szene. \n\n' +
'\n\n\n' +
'das Event "Tech House Germany" am 08.12.2023 im legendären Bootshaus Köln verspricht eine unvergessliche Nacht voller elektrisierender Beats und pulsierender Rhythmen. Jeder DJ bringt seinen einzigartigen Stil und Energie in das Line-up ein, was eine perfekte Mischung aus klassischem und modernem Tech House garantiert. \n\n' +
'Das Bootshaus, bekannt für seine hervorragende Akustik und beeindruckende Lichtshow, bietet die perfekte Kulisse für eine Nacht voller Tanz und Musik. Erleben Sie eine Reise durch die Welt des Tech House, begleitet von den besten Künstlern der Szene. \n\n' +
'\n\n\n' +
'das Event "Tech House Germany" am 08.12.2023 im legendären Bootshaus Köln verspricht eine unvergessliche Nacht voller elektrisierender Beats und pulsierender Rhythmen. Jeder DJ bringt seinen einzigartigen Stil und Energie in das Line-up ein, was eine perfekte Mischung aus klassischem und modernem Tech House garantiert. \n\n' +
'Das Bootshaus, bekannt für seine hervorragende Akustik und beeindruckende Lichtshow, bietet die perfekte Kulisse für eine Nacht voller Tanz und Musik. Erleben Sie eine Reise durch die Welt des Tech House, begleitet von den besten Künstlern der Szene. \n\n' +
'\n\n\n' +
'das Event "Tech House Germany" am 08.12.2023 im legendären Bootshaus Köln verspricht eine unvergessliche Nacht voller elektrisierender Beats und pulsierender Rhythmen. Jeder DJ bringt seinen einzigartigen Stil und Energie in das Line-up ein, was eine perfekte Mischung aus klassischem und modernem Tech House garantiert. \n\n' +
'Das Bootshaus, bekannt für seine hervorragende Akustik und beeindruckende Lichtshow, bietet die perfekte Kulisse für eine Nacht voller Tanz und Musik. Erleben Sie eine Reise durch die Welt des Tech House, begleitet von den besten Künstlern der Szene. \n\n' +
'\n\n\n' +
'Blckbx: \n' +
'NIGHTFUNK \n' +
'FINIQ \n' +
@ -183,10 +178,13 @@ async function getEvent(
Type: 0,
Theme: 0,
FriendList: [],
UserLength: 5,
pic: 'https://www.w3schools.com/w3css/img_lights.jpg',
UserLength: 2121,
pic: 'https://res.cloudinary.com/coin-nft/image/upload/c_limit,q_auto,w_329/f_auto/v1/cache/1/f2/65/f26573682335fe72b50f0f74041736905308345d6043abbac832856b3a4d2246-ZGMwNDMxZTktYTY4NS00OTQ1LWJiYmUtMDRhY2Q0YzUzMjAy?_a=ATCkFAA0',
ButtonAction:
'{"url":"https://www.w3schools.com/w3css/img_lights.jpg"}',
'{"url":"https://res.cloudinary.com/coin-nft/image/upload/c_limit,q_auto,w_329/f_auto/v1/cache/1/f2/65/f26573682335fe72b50f0f74041736905308345d6043abbac832856b3a4d2246-ZGMwNDMxZTktYTY4NS00OTQ1LWJiYmUtMDRhY2Q0YzUzMjAy?_a=ATCkFAA0"}',
minAge: 18,
AddressText: 'Bootshaus / Auenweg 173 / 51063 Cologne',
},
};
@ -227,6 +225,12 @@ async function getEvent(
SourceProp.cached,
resp.response.ButtonAction,
),
minAge: createEventProp(SourceProp.cached, resp.response.minAge),
AddressText: createEventProp(
SourceProp.cached,
resp.response.AddressText,
),
isJoined: createEventProp(SourceProp.cached, 0),
};
//BigDataManager.setEntry('events', event);
@ -329,13 +333,48 @@ function initUndefinedEvent(UUID: EventID): PAEvent {
hq: createEventProp(SourceProp.online),
},
ButtonAction: createEventProp(SourceProp.online),
isJoined: createEventProp(SourceProp.online),
minAge: createEventProp(SourceProp.online),
AddressText: createEventProp(SourceProp.online),
};
}
function joinEvent(UUID: EventID): Promise<boolean> {
return new Promise((resolve, reject) => {
setTimeout(() => {
store.dispatch(appNonSaveVarActions.setJoinedEvent({id:UUID, isJoined: 1}));
getEvent(UUID, true).then(() => {
resolve(true);
}).catch(() => {
reject(false);
});
},1000);
});
}
function quitEvent(UUID: EventID): Promise<boolean> {
return new Promise((resolve, reject) => {
setTimeout(() => {
store.dispatch(appNonSaveVarActions.setJoinedEvent({id:UUID, isJoined: 0}));
resolve(true);
},1000);
});
}
const EventManager = {
getEvent,
getEventSelector,
getEventSelectorPicture,
initUndefinedEvent,
joinEvent,
quitEvent,
};
export default EventManager;

View File

@ -46,9 +46,9 @@ export interface PAEvent {
UserLength: BasicEventProp<number>;
EventBannerPicture: EventBannerPicture;
ButtonAction: BasicEventProp<string>;
//isJoined
//minAge
//AddressText
isJoined: BasicEventProp<number>;
minAge: BasicEventProp<number>;
AddressText: BasicEventProp<string>;
}
export function NumToEventType(num: number): EventType {

View File

@ -19,7 +19,7 @@ export const apiPath = {
export enum apiBackendRequest {
LOGIN = '/user/login',
APP_START = '/appstart',
APP_START = '/user',
GET_USER_PROFILE = '/users/:accountName',
LOGOUT = '/user/logout',
SIGN_UP = '/user/signup',
@ -29,8 +29,7 @@ export enum apiBackendRequest {
REGISTER_STEP_2 = '/verify/email/:xToken/:verifyId',
REGISTER_STEP_FINAL = '/admin/users',
REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK = '/admin/users/validation/accountname',
LOGIN = '/user',
APP_START = '/appstart', */
LOGIN = '/user', */
}
type requestGET = {[key: string]: string};
@ -161,6 +160,8 @@ interface APP_START extends defaultRequest {
path: apiBackendRequest.APP_START;
response: {
accountName: AccountName;
username: Username;
/* TokenValid: boolean;
AccountName: AccountName;
Username: Username;

View File

@ -21,6 +21,9 @@ enum keys {
EventBannerPictureBinaryLQ = 'n',
EventBannerPictureBinaryHQ = 'o',
ButtonAction = 'p',
isJoined = 'q',
minAge = 'r',
AddressText = 's',
}
const name = 'events';
@ -43,6 +46,9 @@ const propsType: {[key in keyof typeof propsDefault]: string} = {
[keys.EventBannerPictureBinaryLQ]: 'data',
[keys.EventBannerPictureBinaryHQ]: 'data',
[keys.ButtonAction]: 'string',
[keys.isJoined]: 'int',
[keys.minAge]: 'int',
[keys.AddressText]: 'string',
};
const propsDefault = {
@ -62,6 +68,9 @@ const propsDefault = {
[keys.EventBannerPictureBinaryLQ]: new ArrayBuffer(0),
[keys.EventBannerPictureBinaryHQ]: new ArrayBuffer(0),
[keys.ButtonAction]: '',
[keys.isJoined]: 0,
[keys.minAge]: 0,
[keys.AddressText]: '',
};
const thisSchema: databaseConf<typeof propsDefault, typeof keys> = {

View File

@ -6,6 +6,13 @@ interface LangDetails {
export default interface LangFormat {
details: LangDetails;
appName: string;
event: {
info: string;
details: string;
tickets: string;
join: string;
quit: string;
};
navigation: {
home: {
profile: {

View File

@ -5,6 +5,13 @@ export const lang: LangFormat = {
langCode: 'en',
langName: 'English',
},
event: {
info: 'INFO',
details: 'DETAILS',
tickets: 'Tickets',
join: 'Join',
quit: 'Quit',
},
appName: 'Party App',
navigation: {
home: {

View File

@ -16,7 +16,7 @@ import ProfileTab, {
ProfileStackNavigatorParamList,
} from './tabs/main/ProfileTab';
import {FadeInView} from '@helper/animations';
import {Animated, View} from 'react-native';
import {Animated, AppState, View} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import {
RegistrationScreenAnim,
@ -30,6 +30,7 @@ import {Text} from '@gluestack-ui/themed';
import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
import {useEffect, useRef} from 'react';
import {animated, useSpring} from '@react-spring/native';
import {apiBackendRequest, makeRequest} from '@helper/request';
export type RootStackNavigatorParamList = {
Home: NavigatorScreenParams<HomeStackNavigatorParamList>;
@ -43,6 +44,32 @@ export default function Navigation() {
const currentUser =
reduxStore.getState().appVariables.preferences.selectedAccount;
useEffect(() => {
console.log('APP NAVIGATION');
makeRequest({
path: apiBackendRequest.APP_START,
response: {
accountName: '',
username: '',
/*
AccountName: '',
Description: '',
FollowersCount: 0,
FollowingCount: 0,
Username: '',
XpLevel: 0,
XpPoints: 0,
AvatarUrl: '',
AccountStatus: 0,
Events: {},
TokenValid: false, */
},
}).then(response => {
console.log(response);
});
}, []);
return (
<Stack.Navigator
screenOptions={{
@ -184,7 +211,7 @@ function CustomTabBar(props: BottomTabBarProps) {
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
zIndex: 100,
position: 'absolute',
position: routeName === 'Calendar' ? 'relative' : 'absolute',
bottom: 0,
borderColor: currentTheme.backgroundDark300,
borderWidth: 3,

View File

@ -50,7 +50,7 @@ function MapTab() {
name="Event"
options={{
animation: 'slide_from_right',
title: 'lang',
title: '',
headerShown: true,
headerStyle: headerStyle,
headerShadowVisible: false,

View File

@ -32,6 +32,10 @@ const LazyHelp = lazy(() =>
import('@pages/profile/help').then(module => ({default: module.Help})),
);
const LazyAbout = lazy(() =>
import('@pages/profile/about').then(module => ({default: module.About})),
);
const Help = () => {
return (
<MySuspenseFallback>
@ -40,10 +44,6 @@ const Help = () => {
);
};
const LazyAbout = lazy(() =>
import('@pages/profile/about').then(module => ({default: module.About})),
);
const About = () => {
return (
<MySuspenseFallback>

View File

@ -1,19 +1,58 @@
import {MyScreenContainer} from '@components/MyScreenContainer';
import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
import {Text} from '@gluestack-ui/themed';
import {RootState} from '@redux/store';
import {Image} from 'react-native';
import {FlatList} from 'react-native';
import {View} from 'react-native';
import {useSelector} from 'react-redux';
const baseUrls = [
'https://www.w3schools.com/w3css/img_lights.jpg',
'https://suburbanmen.com/wp-content/uploads/2021/12/instagram-crush-emilia-bte-20211202-125.jpg',
'https://i.ytimg.com/vi/X0I6PbIWmPo/hqdefault.jpg',
'https://i.ytimg.com/vi/RDrJ1VmRi0w/hqdefault.jpg',
];
const events: ArrayLike<any> | null | undefined = [];
for (let i = 1; i <= 100; i++) {
const randomUrlIndex = Math.floor(Math.random() * baseUrls.length);
events.push({
id: i,
url: baseUrls[randomUrlIndex],
title: 'Bootshaus',
description: '01.12.2023 20:00 Uhr',
});
}
/*
const events = [
{
id: 1,
url: 'https://www.w3schools.com/w3css/img_lights.jpg',
title: 'Bootshaus',
description: '01.12.2023 20:00 Uhr',
},
{
id: 2,
url: 'https://suburbanmen.com/wp-content/uploads/2021/12/instagram-crush-emilia-bte-20211202-125.jpg',
title: 'Bootshaus',
description: '01.12.2023 20:00 Uhr',
},
];
{
id: 3,
url: 'https://i.ytimg.com/vi/X0I6PbIWmPo/hqdefault.jpg',
title: 'Bootshaus',
description: '01.12.2023 20:00 Uhr',
},
{
id: 4,
url: 'https://i.ytimg.com/vi/RDrJ1VmRi0w/hqdefault.jpg',
title: 'Bootshaus',
description: '01.12.2023 20:00 Uhr',
},
];*/
export function CalendarScreen() {
const currentTheme = useSelector(
@ -21,8 +60,41 @@ export function CalendarScreen() {
);
return (
<MyScreenContainer>
<Text>Calendar</Text>
</MyScreenContainer>
<View>
<FlatList
data={events}
keyExtractor={(item, index) => `${item.id}${index}`}
renderItem={({item}) => (
<MyTouchableOpacity
key={item.id}
style={{
margin: 12,
padding: 12,
borderRadius: 10,
backgroundColor: currentTheme.backgroundDark300,
marginBottom: 12,
flexDirection: 'row',
gap: 12,
}}>
<View style={{backgroundColor: currentTheme.backgroundDark200}}>
<Image
style={{
width: 100,
height: 60,
}}
source={{uri: item.url}}
/>
</View>
<View>
<Text size="xl" bold>
{item.title}
</Text>
<Text>{item.description}</Text>
</View>
</MyTouchableOpacity>
)}
/>
</View>
);
}

View File

@ -1,12 +1,16 @@
import {Center, Spinner, Text, View} from '@gluestack-ui/themed';
import {Box, Center, Spinner, Text, View} from '@gluestack-ui/themed';
import {EventID} from '@event/types';
import EventManager from '@event/EventManager';
import {MyScreenContainer} from '@components/MyScreenContainer';
import {SourceProp} from '@user/types';
import MyImage from '@components/MyImage';
import {Image} from 'react-native';
import MyImage, {getImageURL} from '@components/MyImage';
import {Image, Linking} from 'react-native';
import {useEffect, useState} from 'react';
import {useSelector} from 'react-redux';
import {RootState} from '@redux/store';
import {MyButton} from '@components/MyButton';
function EventPageLoading() {
// center also horizontally and vertically
@ -17,48 +21,138 @@ function EventPageLoading() {
);
}
function EventPage({route}: {route: {params: {eventID: EventID}}}) {
function EventPage({
route,
navigation,
}: {
route: {params: {eventID: EventID}};
navigation: any;
}) {
const {eventID} = route.params;
const event = EventManager.getEventSelector(eventID);
if (event.Name.source === SourceProp.online) return <EventPageLoading />;
const lang = useSelector((state: RootState) => state.appVariables.lang.event);
let image = event.EventBannerPicture.hq;
if (image === undefined) {
image = event.EventBannerPicture.lq;
}
const imageUrl =
'https://res.cloudinary.com/coin-nft/image/upload/c_limit,q_auto,w_329/f_auto/v1/cache/1/f2/65/f26573682335fe72b50f0f74041736905308345d6043abbac832856b3a4d2246-ZGMwNDMxZTktYTY4NS00OTQ1LWJiYmUtMDRhY2Q0YzUzMjAy?_a=ATCkFAA0';
const [isJoining, setIsJoining] = useState(false); // for join button (loading)
useEffect(() => {
// Fetch the image dimensions and calculate the aspect ratio
Image.getSize(
imageUrl,
(width, height) => {
const calculatedAspectRatio = width / height;
setAspectRatio(calculatedAspectRatio);
},
error => {
console.error('Error getting image size: ', error);
},
);
}, [imageUrl]);
navigation.setOptions({
title: event.Name.data,
});
}, [event.Name.data]);
if (event.Name.source === SourceProp.online) return <EventPageLoading />;
const imageUrl = getImageURL([
event.EventBannerPicture.hq,
event.EventBannerPicture.lq,
]);
const isJoinedToEvent = event.isJoined.data === 1;
//const imageUrl = 'https://res.cloudinary.com/coin-nft/image/upload/c_limit,q_auto,w_329/f_auto/v1/cache/1/f2/65/f26573682335fe72b50f0f74041736905308345d6043abbac832856b3a4d2246-ZGMwNDMxZTktYTY4NS00OTQ1LWJiYmUtMDRhY2Q0YzUzMjAy?_a=ATCkFAA0';
return (
<MyScreenContainer scrollView={true}>
{
<>
<Text>{event.Name.data}</Text>
<Image
source={{
uri: imageUrl,
}}
style={{width: '100%', height: 400}}
alt="Event banner"
/>
<Text>{event.Description.data}</Text>
<Box
marginBottom={20}
style={{
maxWidth: '100%',
width: 444,
}}>
<MyImage
source={{
uri: imageUrl,
}}
style={{
width: '100%',
height: 250,
borderRadius: 10,
}}
alt="Event banner"
/>
<Text marginTop={10} fontWeight={'100'} color="$textLight400">
{lang.info}
</Text>
<Box
padding={10}
backgroundColor="$backgroundDark300"
borderRadius={10}>
<Text>{event.Description.data}</Text>
</Box>
<Text marginTop={10} fontWeight={'100'} color="$textLight400">
{lang.details}
</Text>
<Box
padding={10}
backgroundColor="$backgroundDark300"
borderRadius={10}>
<Text color="$textLight400">{event.UserLength.data}</Text>
<Text color="$textLight400">{event.minAge.data}</Text>
<Text color="$textLight400">{event.AddressText.data}</Text>
</Box>
<MyButton
type="secondary"
style={{marginTop: 20}}
text={lang.tickets}
onPress={() => {
// open link in browser
if (event.ButtonAction.data === undefined) return;
{
const button = JSON.parse(event.ButtonAction.data);
if (button.url !== undefined) Linking.openURL(button.url);
}
}}
/>
<MyButton
type={isJoinedToEvent ? 'secondary' : 'primary'}
style={{marginTop: 5}}
isLoading={isJoining}
disabled={isJoining}
text={isJoinedToEvent ? lang.quit : lang.join}
onPress={() => {
setIsJoining(true);
if (!isJoinedToEvent) {
EventManager.joinEvent(eventID)
.then(() => {
setIsJoining(false);
})
.catch(() => {
setIsJoining(false);
});
} else {
EventManager.quitEvent(eventID)
.then(() => {
setIsJoining(false);
})
.catch(() => {
setIsJoining(false);
});
}
}}
/>
<Text marginTop={10} fontWeight={'100'} color="$textLight400">
debug
</Text>
<Box
padding={10}
backgroundColor="$backgroundDark300"
borderRadius={10}>
<Text color="$textLight400">{event.StartDate.data}</Text>
<Text color="$textLight400">{event.EndDate.data}</Text>
</Box>
</Box>
</>
}
</MyScreenContainer>

View File

@ -7,11 +7,18 @@ import DisplayMarkerList from '@components/map/DisplayMarkerList';
import getLocationData from '@components/map/cluster/getData';
import {PA_Point} from '@components/map/types';
import {store} from '@redux/store';
import {RootState, store} from '@redux/store';
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
import {Position} from '@rnmapbox/maps/src/types/Position';
import {Dimensions} from 'react-native';
import {MyIconButton} from '@components/MyButton';
import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
import {MyIcon} from '@components/MyIcon';
import {useSelector} from 'react-redux';
import {Button, ButtonIcon} from '@gluestack-ui/themed';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
Mapbox.setAccessToken(
'pk.eyJ1IjoidGl0YW5pdW1iYWNoIiwiYSI6ImNscGgzZGJxMDAwbHQyaXA2N3BtOWUxbWkifQ.x-f8JJxwQHWmPFI3P6Qn-w',
@ -25,6 +32,10 @@ export const Map = () => {
//const [mapMarkers, setMapMarkers] = useState<PA_Point[]>([]); // Add useState for visibleBounds
const [lastDataRerender, setLastDataRerender] = useState(0); // Add useState for visibleBounds
const colors = useSelector(
(state: RootState) => state.nonSaveVariables.theme.colors,
);
const getVisibleBounds = async () => {
// return when lastDataRerender is 300ms ago
const now = Date.now();
@ -124,6 +135,14 @@ export const Map = () => {
projection="globe">
<DisplayMarkerList />
</Mapbox.MapView>
<MapIconButton
MyIconProps={{
name: 'close',
size: 24,
backgroundColor: colors.backgroundDark300,
}}
onPress={() => {}}
/>
</View>
</View>
);
@ -143,3 +162,30 @@ const styles = StyleSheet.create({
flex: 1,
},
});
function MapIconButton({
onPress,
MyIconProps,
}: {
onPress: () => void;
MyIconProps: {
name: string;
color?: string;
size: number;
backgroundColor?: string;
};
}) {
return (
<View
style={{
position: 'absolute',
top: 60,
right: 10,
width: MyIconProps.size * 2,
height: MyIconProps.size * 2,
}}>
<MaterialIcon.Button name="facebook" backgroundColor="#3b5998" />
</View>
);
}

View File

@ -17,6 +17,8 @@ import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
import UserManager from '@user/UserManager';
import MyUserManager from '@user/MyUserManager';
import {apiBackendRequest, makeRequest} from '@helper/request';
import reactStringReplace from 'react-string-replace';
import {passwordOptions, userNameOptions} from '@configs/types';
function UserAvatar() {
return (
@ -262,13 +264,22 @@ export function UpdateUsername() {
);
const navigation = useNavigation<ProfileScreenNavigationProp>();
// TODO: get username from current logged in user
const username = 'Max Mustermann';
const user = UserManager.getUserSelector(
useSelector(
(state: RootState) => state.appVariables.preferences.selectedAccount,
),
);
const [newUsername, setNewUsername] = useState(username);
const [newUsername, setNewUsername] = useState(user.Username.data || '');
const info2Text = reactStringReplace(
lang.changeUsername.info2,
'${minLength}',
() => userNameOptions.minLength.toString(),
);
useEffect(() => {
const changed = username !== newUsername;
const changed = user.Username.data !== newUsername;
navigation.setOptions({
headerRight: () =>
@ -299,7 +310,7 @@ export function UpdateUsername() {
<Text color={currentTheme.textLight100} style={{marginTop: 12}}>
{lang.changeUsername.info}
</Text>
<Text color={currentTheme.textLight100}>{lang.changeUsername.info2}</Text>
<Text color={currentTheme.textLight100}>{info2Text}</Text>
</MyScreenContainer>
);
}
@ -318,6 +329,10 @@ export function UpdatePassword() {
const [newPassword, setNewPassword] = useState('');
const [repeatNewPassword, setRepeatNewPassword] = useState('');
const infoText = reactStringReplace(lang.info, '${minLength}', () =>
passwordOptions.minLength.toString(),
);
useEffect(() => {
const passwordChanged =
currentPassword.length > 0 &&
@ -375,7 +390,7 @@ export function UpdatePassword() {
</View>
<Text color={currentTheme.textLight100} style={{marginTop: 12}}>
{lang.info}
{infoText}
</Text>
<Text color={currentTheme.textLight100}>{lang.info2}</Text>
</MyScreenContainer>

View File

@ -27,7 +27,7 @@ export function Login() {
const [isLoading, setIsLoading] = useState(false);
const [accountName, setAccountName] = useState('anna');
const [password, setPassword] = useState('testtesttest');
const [password, setPassword] = useState('testtesttest1#S');
const loginEnabled = accountName.length > 0 && password.length > 0;

View File

@ -41,6 +41,8 @@ function createNewMyUser(
path: apiBackendRequest.APP_START,
requestGET: {':AccountName': AccountName},
response: {
accountName: '',
username: '',
/*
AccountName: '',
Description: '',