Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public CompanyResponseDTO getCompanyById(@PathVariable Long id) {
}

@GetMapping
@PreAuthorize("hasRole('ADMIN')")
@PreAuthorize("hasAnyRole('ADMIN', 'CUSTOMER', 'DRIVER', 'COMPANY_ADMIN')")
public List<CompanyResponseDTO> getAllCompanies() {
return companyService.getAllCompanies();
}
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/api/companies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import client from "./client";
import type { Company } from "@/types/api";

export async function getCompanies(): Promise<Company[]> {
const response = await client.get<Company[]>("/api/companies");
return response.data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import {borderRadius, fontSize, spacing, ThemeColors} from "@/constants/theme";
export const createStyles = (colors: ThemeColors) =>
StyleSheet.create({
trigger: {
paddingHorizontal: spacing.sm + 4,
paddingVertical: spacing.sm,
marginRight: spacing.sm,
paddingHorizontal: spacing.md,
alignSelf: "stretch",
justifyContent: "center",
backgroundColor: colors.surfaceLight,
borderRadius: borderRadius.sm,
borderWidth: 1,
borderColor: colors.border,
},
triggerText: {
fontSize: fontSize.md,
Expand Down
22 changes: 19 additions & 3 deletions frontend/src/components/AccessibilityMenu/AccessibilityMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export default function AccessibilityMenu() {
const triggerRef = useRef<View>(null);
const { locale, setLocale } = useLocaleStore();
const { mode, colors, toggleMode } = useThemeStore();
const showBlobs = useThemeStore((s) => s.showBlobs);
const toggleBlobs = useThemeStore((s) => s.toggleBlobs);
const { t } = useTranslation();
const styles = useMemo(() => createStyles(colors), [colors]);

Expand Down Expand Up @@ -59,8 +61,6 @@ export default function AccessibilityMenu() {
<TouchableWithoutFeedback onPress={() => setOpen(false)}>
<View style={styles.overlay}>
<View style={[styles.menu, { top: menuTop }]}>
{/* Dark Mode Section */}
<Text style={styles.sectionLabel}>{t("common.darkMode")}</Text>
<View style={styles.row}>
<Text style={styles.rowLabel}>{t("common.darkMode")}</Text>
<TouchableOpacity
Expand All @@ -78,9 +78,25 @@ export default function AccessibilityMenu() {
</TouchableOpacity>
</View>

<View style={styles.row}>
<Text style={styles.rowLabel}>{t("common.blobs")}</Text>
<TouchableOpacity
style={[styles.toggle, showBlobs ? styles.toggleOn : styles.toggleOff]}
onPress={toggleBlobs}
>
<Text
style={[
styles.toggleText,
showBlobs ? styles.toggleTextOn : styles.toggleTextOff,
]}
>
{showBlobs ? t("common.on") : t("common.off")}
</Text>
</TouchableOpacity>
Comment thread
StoynovAngel marked this conversation as resolved.
</View>

<View style={styles.divider} />

{/* Language Section */}
<Text style={styles.sectionLabel}>{t("common.language")}</Text>
{LANGUAGES.map(({ code, labelKey }) => {
const active = locale === code;
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/components/BackButton/BackButton.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {StyleSheet} from "react-native";
import {ThemeColors, spacing, fontSize, fontWeight} from "@/constants/theme";

export const createStyles = (colors: ThemeColors) =>
StyleSheet.create({
button: {
paddingHorizontal: spacing.md,
paddingTop: spacing.md,
position: "absolute",
top: 0,
left: 0,
zIndex: 10,
},
text: {
fontSize: fontSize.lg,
color: colors.primary,
fontWeight: fontWeight.medium,
},
});
20 changes: 20 additions & 0 deletions frontend/src/components/BackButton/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {useMemo} from "react";
import {TouchableOpacity, Text} from "react-native";
import {useThemeStore} from "@/stores/themeStore";
import {createStyles} from "./BackButton.styles";

type Props = {
label: string;
onPress: () => void;
};

export default function BackButton({label, onPress}: Props) {
const colors = useThemeStore((s) => s.colors);
const styles = useMemo(() => createStyles(colors), [colors]);

return (
<TouchableOpacity onPress={onPress} style={styles.button}>
<Text style={styles.text}>{"<"} {label}</Text>
</TouchableOpacity>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { StyleSheet } from "react-native";

export const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
overflow: "hidden",
},
});
57 changes: 57 additions & 0 deletions frontend/src/components/BackgroundShapes/BackgroundShapes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { View, Dimensions } from "react-native";
import { useThemeStore } from "@/stores/themeStore";
import { styles } from "./BackgroundShapes.styles";

const { width: W, height: H } = Dimensions.get("window");
Comment thread
StoynovAngel marked this conversation as resolved.
Outdated

type Blob = {
top: number;
left: number;
width: number;
height: number;
rotation: string;
color: string;
borderRadii: [number, number, number, number];
opacity: number;
scale?: [number, number];
};

const BLOBS: Blob[] = [
{ top: -80, left: -90, width: 220, height: 180, rotation: "-25deg", color: "#00E8C5", borderRadii: [70, 40, 80, 30], opacity: 0.7 },
{ top: -40, left: W - 120, width: 160, height: 200, rotation: "35deg", color: "#FF6B6B", borderRadii: [50, 80, 35, 65], opacity: 0.6 },
{ top: 0.4 * H, left: -70, width: 150, height: 170, rotation: "55deg", color: "#aa9cfe", borderRadii: [65, 45, 75, 35], opacity: 0.5 },
{ top: 0.6 * H, left: W - 80, width: 170, height: 150, rotation: "-40deg", color: "#FFB347", borderRadii: [40, 70, 50, 80], opacity: 0.55 },
{ top: 0.85 * H, left: -60, width: 180, height: 160, rotation: "20deg", color: "#FF8FA3", borderRadii: [75, 35, 60, 50], opacity: 0.5 },
];

export default function BackgroundShapes() {
useThemeStore((s) => s.colors);

return (
<View style={styles.container} pointerEvents="none">
{BLOBS.map((blob, i) => (
<View
key={i}
style={{
position: "absolute",
top: blob.top,
left: blob.left,
width: blob.width,
height: blob.height,
borderTopLeftRadius: (blob.borderRadii[0] / 100) * blob.width,
borderTopRightRadius: (blob.borderRadii[1] / 100) * blob.height,
borderBottomRightRadius: (blob.borderRadii[2] / 100) * blob.width,
borderBottomLeftRadius: (blob.borderRadii[3] / 100) * blob.height,
backgroundColor: blob.color,
opacity: blob.opacity,
transform: [
{ rotate: blob.rotation },
{ scaleX: blob.scale?.[0] ?? 1 },
{ scaleY: blob.scale?.[1] ?? 1 },
],
}}
/>
))}
</View>
);
}
56 changes: 56 additions & 0 deletions frontend/src/components/CompanyCard/CompanyCard.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {StyleSheet} from "react-native";
import {ThemeColors, spacing, fontSize, borderRadius, fontWeight} from "@/constants/theme";

export const createStyles = (colors: ThemeColors) =>
StyleSheet.create({
card: {
backgroundColor: colors.glass,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.glassBorder,
overflow: "hidden",
marginTop: spacing.sm,
},
image: {
width: "100%",
height: 160,
},
content: {
padding: spacing.md,
},
header: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: spacing.xs,
},
name: {
fontSize: fontSize.xl,
fontWeight: fontWeight.semibold,
color: colors.text,
flexShrink: 1,
},
badge: {
backgroundColor: colors.glassSelected,
borderWidth: 1,
borderColor: colors.glassSelectedBorder,
paddingHorizontal: spacing.sm,
paddingVertical: spacing.xs,
borderRadius: borderRadius.sm,
marginLeft: spacing.sm,
},
badgeText: {
fontSize: fontSize.xs,
fontWeight: fontWeight.medium,
color: colors.primary,
},
description: {
fontSize: fontSize.md,
color: colors.textSecondary,
marginBottom: spacing.sm,
},
address: {
fontSize: fontSize.sm,
color: colors.textDisabled,
},
});
41 changes: 41 additions & 0 deletions frontend/src/components/CompanyCard/CompanyCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {useMemo} from "react";
import {View, Text, Image} from "react-native";
import {useThemeStore} from "@/stores/themeStore";
import {createStyles} from "./CompanyCard.styles";
import type {Company} from "@/types/api";

type Props = {
company: Company;
typeLabel: string;
};

export default function CompanyCard({company, typeLabel}: Props) {
const colors = useThemeStore((s) => s.colors);
const styles = useMemo(() => createStyles(colors), [colors]);

return (
<View style={styles.card}>
{company.logoUrl && (
<Image source={{uri: company.logoUrl}} style={styles.image} />
)}
<View style={styles.content}>
<View style={styles.header}>
<Text style={styles.name} numberOfLines={1}>
{company.name}
</Text>
<View style={styles.badge}>
<Text style={styles.badgeText}>{typeLabel}</Text>
</View>
</View>
{company.description && (
<Text style={styles.description} numberOfLines={2}>
{company.description}
</Text>
)}
<Text style={styles.address} numberOfLines={1}>
{company.address}
</Text>
</View>
</View>
);
}
23 changes: 23 additions & 0 deletions frontend/src/components/GlassCard/GlassCard.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {StyleSheet} from "react-native";
import {ThemeColors, spacing, borderRadius} from "@/constants/theme";

export const createStyles = (colors: ThemeColors) =>
StyleSheet.create({
card: {
backgroundColor: colors.glass,
borderRadius: borderRadius.lg + 4,
borderWidth: 1,
borderColor: colors.glassBorder,
padding: spacing.xl,
shadowColor: colors.black,
shadowOffset: {width: 0, height: 4},
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 4,
},
cardPressed: {
backgroundColor: colors.glassSelected,
borderColor: colors.glassSelectedBorder,
transform: [{scale: 0.96}],
},
});
33 changes: 33 additions & 0 deletions frontend/src/components/GlassCard/GlassCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {useMemo, useState, ReactNode} from "react";
import {View, TouchableOpacity, StyleProp, ViewStyle} from "react-native";
import {useThemeStore} from "@/stores/themeStore";
import {createStyles} from "./GlassCard.styles";

type Props = {
children: ReactNode;
onPress?: () => void;
style?: StyleProp<ViewStyle>;
pressedStyle?: StyleProp<ViewStyle>;
};

export default function GlassCard({children, onPress, style, pressedStyle}: Props) {
const colors = useThemeStore((s) => s.colors);
const styles = useMemo(() => createStyles(colors), [colors]);
const [pressed, setPressed] = useState(false);

if (onPress) {
return (
<TouchableOpacity
style={[styles.card, style, pressed && styles.cardPressed, pressed && pressedStyle]}
onPress={onPress}
onPressIn={() => setPressed(true)}
onPressOut={() => setPressed(false)}
activeOpacity={1}
>
{children}
</TouchableOpacity>
);
}

return <View style={[styles.card, style]}>{children}</View>;
}
14 changes: 14 additions & 0 deletions frontend/src/components/ScreenContainer/ScreenContainer.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {StyleSheet} from "react-native";
import {ThemeColors} from "@/constants/theme";

export const createStyles = (colors: ThemeColors) =>
StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
},
centered: {
justifyContent: "center",
alignItems: "center",
},
});
23 changes: 23 additions & 0 deletions frontend/src/components/ScreenContainer/ScreenContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {useMemo, ReactNode} from "react";
import {View} from "react-native";
import {useThemeStore} from "@/stores/themeStore";
import BackgroundShapes from "@/components/BackgroundShapes/BackgroundShapes";
import {createStyles} from "./ScreenContainer.styles";

type Props = {
children: ReactNode;
centered?: boolean;
};

export default function ScreenContainer({children, centered}: Props) {
const colors = useThemeStore((s) => s.colors);
const showBlobs = useThemeStore((s) => s.showBlobs);
const styles = useMemo(() => createStyles(colors), [colors]);

return (
<View style={[styles.container, centered && styles.centered]}>
{showBlobs && <BackgroundShapes />}
{children}
</View>
);
}
Loading
Loading