diff --git a/xtablo-expo/components/tasks/AssigneePicker.tsx b/xtablo-expo/components/tasks/AssigneePicker.tsx
new file mode 100644
index 0000000..9c2ec23
--- /dev/null
+++ b/xtablo-expo/components/tasks/AssigneePicker.tsx
@@ -0,0 +1,140 @@
+import React from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ Modal,
+ FlatList,
+ StyleSheet,
+} from "react-native";
+import { X, Check } from "lucide-react-native";
+import { useThemeColor } from "@/hooks/useThemeColor";
+import { useColorScheme } from "@/hooks/useColorScheme";
+import { TabloMember } from "@/hooks/members";
+
+type AssigneePickerProps = {
+ visible: boolean;
+ onClose: () => void;
+ members: TabloMember[];
+ selectedId: string | null;
+ onSelect: (memberId: string | null) => void;
+};
+
+export default function AssigneePicker({
+ visible,
+ onClose,
+ members,
+ selectedId,
+ onSelect,
+}: AssigneePickerProps) {
+ const colorScheme = useColorScheme();
+ const isDark = colorScheme === "dark";
+ const bgColor = useThemeColor({ light: "#ffffff", dark: "#1f2937" }, "background");
+ const textColor = useThemeColor({ light: "#1f2937", dark: "#f9fafb" }, "text");
+ const subtextColor = useThemeColor({ light: "#6b7280", dark: "#9ca3af" }, "text");
+ const borderColor = isDark ? "#374151" : "#e5e7eb";
+
+ const handleSelect = (id: string | null) => {
+ onSelect(id);
+ onClose();
+ };
+
+ return (
+
+
+
+
+ Assigné à
+
+
+
+
+
+ handleSelect(null)}
+ >
+
+ Non assigné
+ {selectedId === null && }
+
+
+ item.id}
+ renderItem={({ item }) => (
+ handleSelect(item.id)}
+ >
+
+
+ {item.name.charAt(0).toUpperCase()}
+
+
+ {item.name}
+ {selectedId === item.id && }
+
+ )}
+ />
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ justifyContent: "flex-end",
+ backgroundColor: "rgba(0,0,0,0.4)",
+ },
+ sheet: {
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ maxHeight: "60%",
+ paddingBottom: 34,
+ },
+ header: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ padding: 16,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ },
+ title: {
+ fontSize: 17,
+ fontWeight: "700",
+ },
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ paddingVertical: 12,
+ paddingHorizontal: 16,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ gap: 12,
+ },
+ avatar: {
+ width: 32,
+ height: 32,
+ borderRadius: 16,
+ backgroundColor: "#3b82f6",
+ alignItems: "center",
+ justifyContent: "center",
+ },
+ avatarEmpty: {
+ backgroundColor: "transparent",
+ borderWidth: 1.5,
+ borderColor: "#d1d5db",
+ borderStyle: "dashed",
+ },
+ avatarText: {
+ color: "#ffffff",
+ fontSize: 14,
+ fontWeight: "600",
+ },
+ name: {
+ flex: 1,
+ fontSize: 15,
+ },
+});
diff --git a/xtablo-expo/components/tasks/EtapePicker.tsx b/xtablo-expo/components/tasks/EtapePicker.tsx
new file mode 100644
index 0000000..da5dc1b
--- /dev/null
+++ b/xtablo-expo/components/tasks/EtapePicker.tsx
@@ -0,0 +1,114 @@
+import React from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ Modal,
+ FlatList,
+ StyleSheet,
+} from "react-native";
+import { X, Check } from "lucide-react-native";
+import { useThemeColor } from "@/hooks/useThemeColor";
+import { useColorScheme } from "@/hooks/useColorScheme";
+import { Etape } from "@/types/tasks.types";
+
+type EtapePickerProps = {
+ visible: boolean;
+ onClose: () => void;
+ etapes: Etape[];
+ selectedId: string | null;
+ onSelect: (etapeId: string | null) => void;
+};
+
+export default function EtapePicker({
+ visible,
+ onClose,
+ etapes,
+ selectedId,
+ onSelect,
+}: EtapePickerProps) {
+ const colorScheme = useColorScheme();
+ const isDark = colorScheme === "dark";
+ const bgColor = useThemeColor({ light: "#ffffff", dark: "#1f2937" }, "background");
+ const textColor = useThemeColor({ light: "#1f2937", dark: "#f9fafb" }, "text");
+ const subtextColor = useThemeColor({ light: "#6b7280", dark: "#9ca3af" }, "text");
+ const borderColor = isDark ? "#374151" : "#e5e7eb";
+
+ const handleSelect = (id: string | null) => {
+ onSelect(id);
+ onClose();
+ };
+
+ return (
+
+
+
+
+ Étape
+
+
+
+
+
+ handleSelect(null)}
+ >
+ Sans Étape
+ {selectedId === null && }
+
+
+ item.id}
+ renderItem={({ item }) => (
+ handleSelect(item.id)}
+ >
+ {item.title}
+ {selectedId === item.id && }
+
+ )}
+ />
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ justifyContent: "flex-end",
+ backgroundColor: "rgba(0,0,0,0.4)",
+ },
+ sheet: {
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ maxHeight: "50%",
+ paddingBottom: 34,
+ },
+ header: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ padding: 16,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ },
+ title: {
+ fontSize: 17,
+ fontWeight: "700",
+ },
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ paddingVertical: 14,
+ paddingHorizontal: 16,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ },
+ name: {
+ flex: 1,
+ fontSize: 15,
+ },
+});