feat(mobile): register QrTemplate2 Daily Grind and filter UI to active component templates
This commit is contained in:
@@ -33,21 +33,29 @@ export default function QrScreen() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const [selectedKey, setSelectedKey] = useState<string>("qr-4");
|
const availablePresets = Object.values(QR_STAND_PRESETS).filter(
|
||||||
|
(p) => !!COMPONENT_TEMPLATES[p.key]
|
||||||
|
);
|
||||||
|
const [selectedKey, setSelectedKey] = useState<string>(
|
||||||
|
availablePresets[0]?.key || "qr-lumiere"
|
||||||
|
);
|
||||||
const [exportingPng, setExportingPng] = useState(false);
|
const [exportingPng, setExportingPng] = useState(false);
|
||||||
const [exportingPdf, setExportingPdf] = useState(false);
|
const [exportingPdf, setExportingPdf] = useState(false);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const viewShotRef = useRef<any>(null);
|
const viewShotRef = useRef<any>(null);
|
||||||
|
|
||||||
const activePreset: QrStandPreset = (QR_STAND_PRESETS[selectedKey] || Object.values(QR_STAND_PRESETS)[0])!;
|
const activePreset: QrStandPreset =
|
||||||
|
QR_STAND_PRESETS[selectedKey] || availablePresets[0] || Object.values(QR_STAND_PRESETS)[0]!;
|
||||||
|
|
||||||
// Component-based template sistemi
|
// Component-based template sistemi
|
||||||
const TemplateComponent = COMPONENT_TEMPLATES[selectedKey] ?? Object.values(COMPONENT_TEMPLATES)[0];
|
const TemplateComponent =
|
||||||
|
COMPONENT_TEMPLATES[selectedKey] ?? Object.values(COMPONENT_TEMPLATES)[0];
|
||||||
const aspectRatio = TEMPLATE_ASPECT_RATIOS[selectedKey] ?? 1;
|
const aspectRatio = TEMPLATE_ASPECT_RATIOS[selectedKey] ?? 1;
|
||||||
const displayWidth = 300;
|
const displayWidth = 300;
|
||||||
const displayHeight = Math.round(displayWidth / aspectRatio);
|
const displayHeight = Math.round(displayWidth / aspectRatio);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const activeRest = await getActiveRestaurant();
|
const activeRest = await getActiveRestaurant();
|
||||||
@@ -230,14 +238,15 @@ export default function QrScreen() {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Horizontal Theme Selector */}
|
{/* Horizontal Theme Selector */}
|
||||||
{Object.values(QR_STAND_PRESETS).length > 1 && (
|
{availablePresets.length > 1 && (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
horizontal
|
horizontal
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
contentContainerStyle={{ gap: 10, paddingHorizontal: 4, marginBottom: 20 }}
|
contentContainerStyle={{ gap: 10, paddingHorizontal: 4, marginBottom: 20 }}
|
||||||
>
|
>
|
||||||
{Object.values(QR_STAND_PRESETS).map((preset) => {
|
{availablePresets.map((preset) => {
|
||||||
const isSelected = preset.key === selectedKey;
|
const isSelected = preset.key === selectedKey;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
key={preset.key}
|
key={preset.key}
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Svg, {
|
||||||
|
SvgProps,
|
||||||
|
Path,
|
||||||
|
Rect,
|
||||||
|
Circle,
|
||||||
|
G,
|
||||||
|
Ellipse,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
} from "react-native-svg";
|
||||||
|
|
||||||
|
interface QrTemplate2Props extends SvgProps {
|
||||||
|
qrBase64?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QrTemplate2 = ({ qrBase64, ...props }: QrTemplate2Props) => (
|
||||||
|
<Svg
|
||||||
|
viewBox="0 0 400 650"
|
||||||
|
width={300}
|
||||||
|
height={487.5}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{/* Arka Plan */}
|
||||||
|
<Path fill="#252c36" d="M0 0h400v650H0z" />
|
||||||
|
|
||||||
|
{/* Ana Kart */}
|
||||||
|
<Rect
|
||||||
|
width={360}
|
||||||
|
height={610}
|
||||||
|
x={20}
|
||||||
|
y={20}
|
||||||
|
fill="#f6efe2"
|
||||||
|
stroke="#3a2312"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
rx={20}
|
||||||
|
/>
|
||||||
|
<Rect
|
||||||
|
width={344}
|
||||||
|
height={594}
|
||||||
|
x={28}
|
||||||
|
y={28}
|
||||||
|
fill="none"
|
||||||
|
stroke="#8c6239"
|
||||||
|
strokeOpacity={0.4}
|
||||||
|
rx={14}
|
||||||
|
/>
|
||||||
|
<Rect
|
||||||
|
width={336}
|
||||||
|
height={586}
|
||||||
|
x={32}
|
||||||
|
y={32}
|
||||||
|
fill="none"
|
||||||
|
stroke="#8c6239"
|
||||||
|
strokeOpacity={0.25}
|
||||||
|
strokeWidth={0.5}
|
||||||
|
rx={10}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Sol Üst Botanik Dal */}
|
||||||
|
<G fill="none" stroke="#3a2312" strokeLinecap="round" strokeWidth={1.05}>
|
||||||
|
<Path d="M36 36c11.25 11.25 18.75 26.25 22.5 48.75" />
|
||||||
|
<Path
|
||||||
|
fill="#eadcc7"
|
||||||
|
d="M43.5 45c-3.75-7.5 7.5-10.5 9-3 0 7.5-9 3-9 3Zm6 11.25C45 51 57 46.5 60 53.25c0 6.75-10.5 3-10.5 3Zm4.5 13.5C60 64.5 69.75 72 64.5 78c-6 4.5-10.5-8.25-10.5-8.25Z"
|
||||||
|
/>
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Sağ Üst Kahve İkonu */}
|
||||||
|
<G transform="translate(340 52)">
|
||||||
|
<Circle r={32} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} />
|
||||||
|
<Circle
|
||||||
|
r={26}
|
||||||
|
fill="#f6efe2"
|
||||||
|
stroke="#8c6239"
|
||||||
|
strokeDasharray="2 2"
|
||||||
|
strokeWidth={0.8}
|
||||||
|
/>
|
||||||
|
<Circle r={21} fill="#7a4b26" stroke="#3a2312" strokeWidth={1.4} />
|
||||||
|
<Path fill="#f6efe2" d="M0 10C-8 4-4-6 0-12 4-6 8 4 0 10" />
|
||||||
|
<Path fill="#7a4b26" d="M0 4C-5 0-2-5 0-8 2-5 5 0 0 4" />
|
||||||
|
<Circle cy={-14} r={1.8} fill="#f6efe2" />
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Sol Orta Kahve Bardağı */}
|
||||||
|
<G transform="translate(48 250)">
|
||||||
|
<Circle r={26} fill="#eadcc7" stroke="#3a2312" />
|
||||||
|
<Circle r={17} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} />
|
||||||
|
<Path fill="#f6efe2" d="M-5-3c-3-4 5-7 5-1 0-6 8-3 5 1L0 7z" />
|
||||||
|
<Path fill="none" stroke="#3a2312" strokeWidth={1.5} d="M17-4c6 0 6 8 0 8" />
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Sağ Dal */}
|
||||||
|
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
|
||||||
|
<Path d="M352 230c-7 21-10.5 49-3.5 77" />
|
||||||
|
<Path
|
||||||
|
fill="#eadcc7"
|
||||||
|
d="M349.2 247.5c8.4-7 15.4 2.1 5.6 7.7-5.6 0-5.6-7.7-5.6-7.7Zm-2.8 24.5c-9.8-8.4-15.4 1.4-7 7 7 0 7-7 7-7Zm2.1 19.6c9.1-7 13.3 2.8 4.9 8.4-4.9 0-4.9-8.4-4.9-8.4Z"
|
||||||
|
/>
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Dekoratif Çizgi */}
|
||||||
|
<Path
|
||||||
|
fill="none"
|
||||||
|
stroke="#8c6239"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeWidth={1.2}
|
||||||
|
d="M142 66c6-2 12 2 18 0m80 0c6 2 12-2 18 0"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Sol Alt Dal */}
|
||||||
|
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
|
||||||
|
<Path d="M42 601.5c13-26 9.75-52 0-71.5" />
|
||||||
|
<Path
|
||||||
|
fill="#eadcc7"
|
||||||
|
d="M47.2 549.5c10.4-9.75 17.55 0 6.5 7.8Zm2.6 26c11.7-9.75 18.2 1.3 5.2 9.1Z"
|
||||||
|
/>
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Kahve Çekirdekleri (arka plan süsü) */}
|
||||||
|
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-20 1741.206 -8.75) scale(.8)">
|
||||||
|
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
|
||||||
|
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
|
||||||
|
</G>
|
||||||
|
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(35 -862.106 494.982) scale(.8)">
|
||||||
|
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
|
||||||
|
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
|
||||||
|
</G>
|
||||||
|
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-45 602.558 -225.588) scale(.7)">
|
||||||
|
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
|
||||||
|
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Sağ Alt Fincan */}
|
||||||
|
<G transform="translate(325 590)">
|
||||||
|
<Ellipse cy={18} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} rx={28} ry={7} />
|
||||||
|
<Path fill="#f6efe2" stroke="#3a2312" strokeWidth={1.4} d="M-18 2c0 14 36 14 36 0Z" />
|
||||||
|
<Ellipse cy={2} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} rx={18} ry={4} />
|
||||||
|
<Path fill="none" stroke="#3a2312" strokeWidth={1.3} d="M16 4c8 0 8 8 0 10" />
|
||||||
|
<Path fill="none" stroke="#8c6239" strokeLinecap="round" d="M-6-4c-2-5 2-8 0-13M2-5c-2-5 2-8 0-14" />
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* QR Köşe Çerçeveleri */}
|
||||||
|
<Path
|
||||||
|
fill="none"
|
||||||
|
stroke="#3a2312"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M80 205c0-10 0-10 10-10m230 10c0-10 0-10-10-10M80 445c0 10 0 10 10 10m230-10c0 10 0 10-10 10"
|
||||||
|
/>
|
||||||
|
<Path stroke="#8c6239" strokeWidth={0.8} d="M145 608h30m50 0h30" />
|
||||||
|
|
||||||
|
{/* QR Placeholder / Gerçek QR */}
|
||||||
|
<G transform="translate(90 215)">
|
||||||
|
<Rect width={220} height={220} fill="#fbf8f2" stroke="#d8c7b0" strokeWidth={1.5} rx={20} />
|
||||||
|
{qrBase64 ? (
|
||||||
|
<Image
|
||||||
|
href={`data:image/png;base64,${qrBase64}`}
|
||||||
|
x={10}
|
||||||
|
y={10}
|
||||||
|
width={200}
|
||||||
|
height={200}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Rect
|
||||||
|
width={200}
|
||||||
|
height={200}
|
||||||
|
x={10}
|
||||||
|
y={10}
|
||||||
|
fill="#f5efe6"
|
||||||
|
stroke="#d8c7b0"
|
||||||
|
strokeDasharray="4 3"
|
||||||
|
rx={14}
|
||||||
|
/>
|
||||||
|
<Circle cx={110} cy={98} r={18} fill="#fbf8f2" stroke="#8c6239" />
|
||||||
|
<G fill="#3a2312" transform="matrix(.65 0 0 .65 110 98)">
|
||||||
|
<Ellipse cx={-5} cy={2} rx={7} ry={5} transform="rotate(-30)" />
|
||||||
|
<Ellipse cx={5} rx={7} ry={5} transform="rotate(40)" />
|
||||||
|
</G>
|
||||||
|
<Text
|
||||||
|
x={110}
|
||||||
|
y={132}
|
||||||
|
fill="#8c6239"
|
||||||
|
fontFamily="Inter, Arial, sans-serif"
|
||||||
|
fontSize={11}
|
||||||
|
fontWeight={700}
|
||||||
|
letterSpacing={1}
|
||||||
|
textAnchor="middle"
|
||||||
|
>
|
||||||
|
{"QR KOD ALANI"}
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</G>
|
||||||
|
|
||||||
|
{/* Metinler */}
|
||||||
|
<G textAnchor="middle">
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={70}
|
||||||
|
fill="#3a2312"
|
||||||
|
fontFamily="'Playfair Display', Georgia, serif"
|
||||||
|
fontSize={14}
|
||||||
|
fontStyle="italic"
|
||||||
|
fontWeight={700}
|
||||||
|
letterSpacing={4}
|
||||||
|
>
|
||||||
|
{"THE"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={114}
|
||||||
|
fill="#2c1a0e"
|
||||||
|
fontFamily="'Playfair Display', Georgia, serif"
|
||||||
|
fontSize={34}
|
||||||
|
fontWeight={800}
|
||||||
|
letterSpacing={0.5}
|
||||||
|
>
|
||||||
|
{"The Daily Grind"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={146}
|
||||||
|
fill="#3a2312"
|
||||||
|
fontFamily="Inter, Arial, sans-serif"
|
||||||
|
fontSize={13}
|
||||||
|
fontWeight={800}
|
||||||
|
letterSpacing={3}
|
||||||
|
>
|
||||||
|
{"COFFEE & KITCHEN"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={488}
|
||||||
|
fill="#2c1a0e"
|
||||||
|
fontFamily="Inter, Arial, sans-serif"
|
||||||
|
fontSize={19}
|
||||||
|
fontWeight={900}
|
||||||
|
letterSpacing={1.5}
|
||||||
|
>
|
||||||
|
{"SCAN TO VIEW MENU"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={520}
|
||||||
|
fill="#3a2312"
|
||||||
|
fontFamily="Inter, Arial, sans-serif"
|
||||||
|
fontSize={10.5}
|
||||||
|
fontWeight={700}
|
||||||
|
letterSpacing={0.5}
|
||||||
|
>
|
||||||
|
{"DAILY GRIND CAFE | WIFI: DAILY_GRIND_GUEST"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={542}
|
||||||
|
fill="#8c6239"
|
||||||
|
fontFamily="Inter, Arial, sans-serif"
|
||||||
|
fontSize={9}
|
||||||
|
fontWeight={600}
|
||||||
|
letterSpacing={1}
|
||||||
|
>
|
||||||
|
{"\u015E\u0130FRE: coffee2026 \u2022 MASA NO: 04"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
x={200}
|
||||||
|
y={611}
|
||||||
|
fill="#3a2312"
|
||||||
|
fontFamily="'Playfair Display', Georgia, serif"
|
||||||
|
fontSize={11}
|
||||||
|
fontStyle="italic"
|
||||||
|
fontWeight={700}
|
||||||
|
letterSpacing={2}
|
||||||
|
>
|
||||||
|
{"EST. 2018"}
|
||||||
|
</Text>
|
||||||
|
</G>
|
||||||
|
</Svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default QrTemplate2;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import type { SvgProps } from "react-native-svg";
|
import type { SvgProps } from "react-native-svg";
|
||||||
import QrTemplateLumiere from "./QrTemplateLumiere";
|
import QrTemplateLumiere from "./QrTemplateLumiere";
|
||||||
|
import QrTemplate2 from "./QrTemplate2";
|
||||||
import QrTemplate3 from "./QrTemplate3";
|
import QrTemplate3 from "./QrTemplate3";
|
||||||
|
|
||||||
export interface QrTemplateProps extends SvgProps {
|
export interface QrTemplateProps extends SvgProps {
|
||||||
@@ -13,11 +14,14 @@ export const COMPONENT_TEMPLATES: Record<
|
|||||||
React.FC<QrTemplateProps>
|
React.FC<QrTemplateProps>
|
||||||
> = {
|
> = {
|
||||||
"qr-lumiere": QrTemplateLumiere,
|
"qr-lumiere": QrTemplateLumiere,
|
||||||
|
"qr-2": QrTemplate2,
|
||||||
"qr-3": QrTemplate3,
|
"qr-3": QrTemplate3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Her template'in aspect ratio'su (width/height)
|
// Her template'in aspect ratio'su (width/height)
|
||||||
export const TEMPLATE_ASPECT_RATIOS: Record<string, number> = {
|
export const TEMPLATE_ASPECT_RATIOS: Record<string, number> = {
|
||||||
"qr-lumiere": 1, // 600x600 = 1:1
|
"qr-lumiere": 1, // 600x600 = 1:1
|
||||||
|
"qr-2": 400 / 650, // 400x650 = standart kart
|
||||||
"qr-3": 400 / 650, // 400x650 = standart kart
|
"qr-3": 400 / 650, // 400x650 = standart kart
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,20 @@ export const QR_STAND_PRESETS: Record<string, QrStandPreset> = {
|
|||||||
subText: "#e5c378",
|
subText: "#e5c378",
|
||||||
dividerColor: "rgba(212, 175, 55, 0.3)",
|
dividerColor: "rgba(212, 175, 55, 0.3)",
|
||||||
},
|
},
|
||||||
|
"qr-2": {
|
||||||
|
key: "qr-2",
|
||||||
|
name: "The Daily Grind (QR-2)",
|
||||||
|
categoryName: "Özel Masa Kartı",
|
||||||
|
svgTemplateUrl: "/qr-2.svg",
|
||||||
|
aspectRatio: "400/650",
|
||||||
|
bgGradient: "radial-gradient(circle at 50% 50%, #252c36 0%, #171c22 100%)",
|
||||||
|
plaqueColor: "#f6efe2",
|
||||||
|
borderAccent: "#3a2312",
|
||||||
|
accentText: "#8c6239",
|
||||||
|
headerText: "#2c1a0e",
|
||||||
|
subText: "#3a2312",
|
||||||
|
dividerColor: "rgba(140, 98, 57, 0.3)",
|
||||||
|
},
|
||||||
"qr-3": {
|
"qr-3": {
|
||||||
key: "qr-3",
|
key: "qr-3",
|
||||||
name: "Pizzeria Bella Napoli (QR-3)",
|
name: "Pizzeria Bella Napoli (QR-3)",
|
||||||
@@ -108,3 +122,4 @@ export const QR_STAND_PRESETS: Record<string, QrStandPreset> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user