Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"private": true,
"dependencies": {
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
"@expo-google-fonts/exo-2": "^0.4.2",
"@expo-google-fonts/inter": "^0.2.3",
"@expo/vector-icons": "^14.1.0",
"@kolking/react-native-avatar": "^2.1.4",
Expand All @@ -24,6 +25,7 @@
"expo-dev-client": "~5.2.4",
"expo-font": "~13.3.2",
"expo-haptics": "~14.1.4",
"expo-linear-gradient": "^15.0.7",
"expo-linking": "~7.1.7",
"expo-localization": "~16.1.6",
"expo-router": "~5.1.6",
Expand Down
8 changes: 2 additions & 6 deletions src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import React, { useEffect, useState } from 'react'
import { I18nextProvider } from 'react-i18next'
import { Provider } from 'react-redux'
import { MaintenanceScreen, LoadingScreen, AppUpdatePopup } from '@/components'
// eslint-disable-next-line camelcase
import { useFonts, Inter_400Regular } from '@expo-google-fonts/inter'
import { useCustomFonts } from '@/hooks'
import RootContainer from '@/components/RootContainer'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import * as Sentry from '@sentry/react-native'
Expand Down Expand Up @@ -72,10 +71,7 @@ const RootLayout = () => {

// Specify the type of the state to be either null or an EnhancedStore instance
const [reduxStore, setReduxStore] = useState<EnhancedStore<RootState> | null>(null)
let [fontsLoaded] = useFonts({
// eslint-disable-next-line camelcase
Inter: Inter_400Regular,
})
const { fontsLoaded } = useCustomFonts()

useEffect(() => {
initStore().then((store) => {
Expand Down
7 changes: 4 additions & 3 deletions src/app/welcome/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import RootImageBackground from '@/components/RootImageBackground'
Copy link
Collaborator

@amrmelsayed amrmelsayed Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RootImageBackground has two platform specific implementations, a web version and native version (.tsx, .web.tsx), and they are getting replaced with a single version, was this done on purpose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RootImageBackground.web.tsx is there but seems to be not used at all in any place.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ajmaljalal that's a platform specific extension, have a look here https://docs.expo.dev/router/advanced/platform-specific-modules/


import WelcomeRootImageBackground from '@/components/welcome/WelcomRootImageBackground'
import { useAuth } from '@/hooks'
import { Redirect, Slot } from 'expo-router'
import React from 'react'
Expand All @@ -18,11 +19,11 @@ export const WelcomeLayout = () => {
}

return (
<RootImageBackground>
<WelcomeRootImageBackground>
<View className='flex-1'>
<Slot />
</View>
</RootImageBackground>
</WelcomeRootImageBackground>
)
}

Expand Down
210 changes: 142 additions & 68 deletions src/app/welcome/index.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,174 @@
import { LogoIcon, LogoTextIcon } from '@/components/svg'
import { LogoIcon } from '@/components/svg'
import ActionButtons from '@/components/ActionButtons'
import StyledText from '@/components/StyledText'
import TermsAndPrivacy from '@/components/TermsAndPrivacy'
import { ENButton, WelcomeFeatureRow, WelcomeFooter } from '@/components'
import { useDirection, useGuest, useScreenInfo } from '@/hooks'
import { RootState } from '@/store'
import { createGeneralThemedStyles } from '@/utils'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { Pressable, View } from 'react-native'
import { View, Text } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import { useRouter } from 'expo-router'
import { LinearGradient } from 'expo-linear-gradient'

const Welcome: React.FC = () => {
const router = useRouter()
const { t } = useTranslation()
const insets = useSafeAreaInsets()

const { guestLoading, handleGuestLogin } = useGuest()
const { isRTL } = useDirection()
const { isSmallScreen, width } = useScreenInfo()
const theme = useSelector((state: RootState) => state.theme.theme)
const generalStyle = createGeneralThemedStyles(theme, isRTL, isSmallScreen, width)


return (
<View className='flex-1'>
<View className={`flex-1 w-full flex ${isSmallScreen ? 'flex-col' : 'flex-row'} justify-center items-center`}>
<View className={`${isSmallScreen ? 'w-full h-auto' : 'w-[70%] h-full'} justify-between p-6`}>
<View className={`${isSmallScreen ? 'flex-col' : 'flex-row'} items-center ${isSmallScreen ? 'mb-6' : ''}`}>
<LogoIcon fill={theme.iconFill} width={52} height={52} />
<LogoTextIcon
fill={theme.logoColor}
width={81}
className={`${isRTL || isSmallScreen ? '' : 'ml-2'} ${isRTL && !isSmallScreen ? 'mr-2' : ''}`}
/>
<LinearGradient
colors={['rgba(255, 255, 255, 0.8)', 'rgba(255, 255, 255, 1)', 'rgba(255, 255, 255, 1)']}
locations={[0, 0.6, 1]}
style={{ flex: 1 }}
>
<View
className={`absolute w-full px-6 flex ${isRTL ? 'items-start' : 'items-end'} z-50`}
style={{ top: Math.max(insets.top, 24) + 12 }}
>
<ActionButtons isTop={true} />
</View>
<View className='flex-1 w-full flex flex-col justify-center items-center p-6'>
<View className='w-full max-w-[400px] items-center'>
<View className='items-center mb-4'>
<LogoIcon fill={theme.darkGreenColor} width={64} height={64} />
</View>
<View>
<StyledText variant='h1' className='font-normal' color={theme.textColor}>
{t('greeting')}
<View className='items-center mb-6'>
<StyledText
variant='h3'
textAlign='center'
className='uppercase tracking-widest'
style={{ color: theme.darkGreenColor, marginBottom: 6, fontFamily: 'Exo2' }}
>
{t('welcomeHeadingSmall', { defaultValue: t('greeting') })}
</StyledText>
<StyledText variant='h1' className='font-bold' color='yellow'>
{t('ansariChat')}
<StyledText
variant='h1'
textAlign='center'
style={{ color: theme.darkGreenColor, width: 500, fontFamily: 'Exo2-Bold' }}
>
{t('welcomeHeadingMain', { defaultValue: t('ansariChat') })}
</StyledText>
</View>
<View>{!isSmallScreen && <ActionButtons isTop={false} />}</View>
</View>
<View
className={`${isSmallScreen ? 'w-full h-auto' : 'w-[30%] h-full my-auto'} justify-center items-center p-6 ${
isSmallScreen ? 'bg-transparent' : ''
}`}
style={{
backgroundColor: isSmallScreen ? undefined : theme.backgroundColor,
}}
>
<View className='w-full items-center px-[10%]'>
<StyledText variant='h2' className='mb-4'>
{t('getStarted')}
</StyledText>
<Pressable
style={[generalStyle.buttonPrimary, generalStyle.fullWidth]}
onPress={() => router.push('/login')}
>
<StyledText style={generalStyle.buttonPrimaryText}>{t('login')}</StyledText>
</Pressable>
<Pressable
className='border'
style={[
generalStyle.buttonPrimary,
generalStyle.fullWidth,
{
backgroundColor: theme.popupBackgroundColor,
borderColor: theme.buttonSecondaryBorderColor,
},
]}
onPress={() => router.push('/register')}
>
<StyledText style={generalStyle.buttonSecondaryText}>{t('register')}</StyledText>
</Pressable>
<Pressable
style={[
generalStyle.buttonSecondary,
generalStyle.fullWidth,
guestLoading && generalStyle.buttonDisabled,
]}
onPress={handleGuestLogin}
disabled={guestLoading}


<View
className='rounded-[16px] p-4 mb-[34px]'
style={{
borderWidth: 1,
borderColor: theme.darkGreenColor,
}}
>
<View
style={{
width: 230,
}}
>
<StyledText style={[generalStyle.buttonSecondaryText, guestLoading && generalStyle.buttonTextDisabled]}>
{guestLoading ? t('login:submitting') : t('login:guestLogin')}
</StyledText>
</Pressable>
<Text
className='text-[16px] leading-[24px] text-center'
style={{
color: theme.blackColor,
fontStyle: 'italic',
fontFamily: 'Exo2-Bold-Italic',
}}
>
{t('welcomeBlurb', {
defaultValue:
'Built by Muslims, trained with care - designed to guide with sources, not guesses.',
})}
</Text>
</View>
</View>

<View className='w-full mb-8'>
<View className={`flex-col ${isRTL ? 'items-end' : 'items-start'} gap-3`}>
<WelcomeFeatureRow
iconName="information"
text={t('welcomeFeatureSourceBased', { defaultValue: 'Get Source-Based Guidance Anytime' })}
/>
<WelcomeFeatureRow
iconName="chat"
text={t('welcomeFeatureSaveChats', {
defaultValue: 'Save your chats and pick up where you left off.',
})}
/>
<WelcomeFeatureRow
iconName="check"
text={t('welcomeFeatureQuickEasy', { defaultValue: 'Quick and easy registration' })}
/>
<WelcomeFeatureRow
iconName="logo"
text={t('welcomeFeatureJoinToday', { defaultValue: 'Join Ansari today!' })}
/>
</View>
</View>
<View className='w-full items-center'>
<ENButton
text={t('createAccount', { defaultValue: 'Create an account' })}
onClick={() => router.push('/register')}
isSubmitting={false}
buttonStyle={{
marginBottom: 12,
borderRadius: 16,
width: '100%',
paddingVertical: 20,
backgroundColor: theme.darkGreenColor,
alignItems: 'center',
}}
buttonTextStyle={{
fontSize: 20,
color: theme.whiteColor,
}}
/>
<ENButton
text={t('logInCta', { defaultValue: 'Log-in' })}
onClick={() => router.push('/login')}
isSubmitting={false}
buttonStyle={{
...generalStyle.buttonSecondary,
marginBottom: 12,
borderRadius: 16,
width: '100%',
paddingVertical: 20,
backgroundColor: 'rgba(22,160,133, 0.4)',
alignItems: 'center',
borderWidth: 0,

}}
buttonTextStyle={{
color: theme.blackColor,
fontSize: 20,
}}
/>
<ENButton
text={t('continueAsGuestLimited', { defaultValue: 'Continue as guest (limited access)' })}
submittingText={t('login:submitting')}
onClick={handleGuestLogin}
isSubmitting={guestLoading}
buttonStyle={{
backgroundColor: 'transparent',
marginTop: 4,
}}
buttonTextStyle={{
color: theme.blackColor,
fontSize: 14,
textAlign: 'center',
}}
/>
</View>
</View>
<View className='absolute bottom-6'>
<TermsAndPrivacy marginLeft={0} />
</View>
</View>
</View>
<WelcomeFooter />
</LinearGradient>
)
}

Expand Down
Binary file added src/assets/images/welcome-background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/components/buttons/ENButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDirection, useScreenInfo } from '@/hooks'
import { RootState } from '@/store'
import { createGeneralThemedStyles } from '@/utils'
import React, { useState } from 'react'
import { Pressable, Text, ViewStyle } from 'react-native'
import { Pressable, Text, TextStyle, ViewStyle } from 'react-native'
import { useSelector } from 'react-redux'

interface Props {
Expand All @@ -12,8 +12,8 @@ interface Props {
isSubmitting?: boolean
buttonStyle?: ViewStyle
buttonHoverStyle?: ViewStyle
buttonTextStyle?: ViewStyle
buttonHoverTextStyle?: ViewStyle
buttonTextStyle?: TextStyle
buttonHoverTextStyle?: TextStyle
}

const ENButton: React.FC<Props> = ({
Expand Down
3 changes: 3 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ export { default as MessageBubble } from './chat/MessageBubble'
export { default as PromptCard } from './prompts/PromptCard'
export { default as PromptList } from './prompts/PromptList'
export { default as ENButton } from './buttons/ENButton'
export { default as WelcomeFeatureRow } from './welcome/WelcomeFeatureRow'
export { default as WelcomeFooter } from './welcome/WelcomeFooter'
export { default as WelcomeRootImageBackground } from './welcome/WelcomRootImageBackground'
17 changes: 17 additions & 0 deletions src/components/welcome/WelcomRootImageBackground.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current app background is greyish, is the whole app switching to the light background theme? How do the other pages look at the moment including the actual login and account registration pages?

Copy link
Contributor Author

@Ajmaljalal Ajmaljalal Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, the current design change is only for the welcome page and all other pages including the login and the registration pages looks exactly as before. I am not 100% sure if we want to implement this. It introduces inconsistencies to the general theme of the app.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { ImageBackground } from 'react-native'

interface WelcomeRootImageBackgroundProps {
children: React.ReactNode
className?: string
}

const WelcomeRootImageBackground: React.FC<WelcomeRootImageBackgroundProps> = ({ children, className }) => {
return (
<ImageBackground source={require('@/assets/images/welcome-background.png')} className={`flex-1 bg-white ${className}`}>
{children}
</ImageBackground>
)
}

export default WelcomeRootImageBackground
Loading