diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index 3805014..a5e5a69 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -6864,6 +6864,18 @@ "tr": "Satış Sipariş Kalemleri", "en": "Sales Order Items" }, + { + "resourceName": "Platform", + "key": "App.Dark", + "tr": "Karanlık", + "en": "Dark" + }, + { + "resourceName": "Platform", + "key": "App.Light", + "tr": "Açık", + "en": "Light" + }, { "resourceName": "Platform", "key": "Public.about.description.closing", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index eece49c..e42e5d7 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -421,7 +421,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency Visible = true, IsActive = true, AllowSearch = true, - ValidationRuleJson = DefaultValidationRuleEmailJson, + ValidationRuleJson = DefaultValidationRuleEmailRequiredJson, ColumnCustomizationJson = DefaultColumnCustomizationJson, PermissionJson = DefaultFieldPermissionJson(TenantManagementPermissions.Tenants.Create, TenantManagementPermissions.Tenants.Default, TenantManagementPermissions.Tenants.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson diff --git a/ui/src/components/layouts/PublicLayout.tsx b/ui/src/components/layouts/PublicLayout.tsx index 1505efc..73e001f 100644 --- a/ui/src/components/layouts/PublicLayout.tsx +++ b/ui/src/components/layouts/PublicLayout.tsx @@ -1,7 +1,7 @@ import View from '@/views/Views' import React, { useEffect, useState } from 'react' import { useLocation, Link } from 'react-router-dom' -import { FaFacebook, FaTwitter, FaLinkedin, FaInstagram } from 'react-icons/fa'; +import { FaFacebook, FaTwitter, FaLinkedin, FaInstagram } from 'react-icons/fa' import { LuMenu, LuX, @@ -14,13 +14,17 @@ import { LuPhone, LuMapPin, LuMail, -} from 'react-icons/lu'; + LuMoon, + LuSun, +} from 'react-icons/lu' import Logo from '@/views/public/Logo' import { ROUTES_ENUM } from '@/routes/route.constant' import { useLocalization } from '@/utils/hooks/useLocalization' import LanguageSelector from '../template/LanguageSelector' import Demo from '@/views/public/Demo' import { ScrollContext } from '@/contexts/ScrollContext' +import useDarkMode from '@/utils/hooks/useDarkmode' +import { THEME_ENUM } from '@/constants/theme.constant' interface NavLink { resourceKey?: string @@ -33,6 +37,7 @@ interface NavLink { const PublicLayout = () => { const location = useLocation() const { translate } = useLocalization() + const [isDarkMode, setThemeMode] = useDarkMode() const [isOpen, setIsOpen] = useState(false) const [scrolled, setScrolled] = useState(false) @@ -109,6 +114,38 @@ const PublicLayout = () => { const isLoginLink = (resourceKey?: string) => resourceKey === 'Public.nav.giris' + const themeToggle = ( +
+ + + +
+ ) + const isActiveLink = (path?: string) => { if (!path) return false if (path === ROUTES_ENUM.public.home) return location.pathname === path @@ -137,20 +174,18 @@ const PublicLayout = () => { const active = isActiveLink(link.path) const baseClass = 'relative flex items-center gap-1.5 px-3 py-2 text-sm font-medium rounded-md transition-all duration-200 group' - const activeClass = active - ? 'text-white' - : 'text-gray-300 hover:text-white' + const activeClass = active ? 'text-white' : 'text-gray-300 hover:text-white' return link.path ? ( - + {link.icon && ( )} {link.name} @@ -183,6 +218,7 @@ const PublicLayout = () => { {/* Right side: Language + Login */}
+ {themeToggle}
{navLinks .filter((l) => isLoginLink(l.resourceKey)) @@ -262,13 +298,18 @@ const PublicLayout = () => { }} className="flex items-center gap-2.5 px-3 py-2.5 text-sm font-medium text-gray-300 hover:bg-white/5 hover:text-white rounded-md transition-colors text-left" > - {link.icon && } + {link.icon && ( + + )} {link.name} ) })}
- +
+ + {themeToggle} +
@@ -440,12 +481,14 @@ const PublicLayout = () => { {/* Contact Info */}
-

- {translate('::App.Contact')} -

+

{translate('::App.Contact')}

  • - + {translate('::Public.footer.address')}
  • diff --git a/ui/src/components/orders/BillingControls.tsx b/ui/src/components/orders/BillingControls.tsx index 0cee43d..298b09a 100644 --- a/ui/src/components/orders/BillingControls.tsx +++ b/ui/src/components/orders/BillingControls.tsx @@ -33,7 +33,7 @@ export const BillingControls: React.FC = ({ return (
    @@ -41,8 +41,8 @@ export const BillingControls: React.FC = ({
    - - + + {translate('::Public.products.billingcycle')}
    @@ -55,8 +55,8 @@ export const BillingControls: React.FC = ({ globalBillingCycle === 'monthly' ? 'bg-blue-600 text-white shadow-md' : hasCartItems - ? 'bg-gray-200 text-gray-400 cursor-not-allowed' - : 'bg-gray-100 text-gray-700 hover:bg-gray-200' + ? 'bg-gray-200 text-gray-400 cursor-not-allowed dark:bg-gray-800 dark:text-gray-500' + : 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700' }`} title={ hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined @@ -71,8 +71,8 @@ export const BillingControls: React.FC = ({ globalBillingCycle === 'yearly' ? 'bg-blue-600 text-white shadow-md' : hasCartItems - ? 'bg-gray-200 text-gray-400 cursor-not-allowed' - : 'bg-gray-100 text-gray-700 hover:bg-gray-200' + ? 'bg-gray-200 text-gray-400 cursor-not-allowed dark:bg-gray-800 dark:text-gray-500' + : 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700' }`} title={ hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined @@ -86,8 +86,8 @@ export const BillingControls: React.FC = ({
    - - + + {translate('::Public.products.period')}
    @@ -95,10 +95,10 @@ export const BillingControls: React.FC = ({
    -
    +
    {globalPeriod} - + {globalBillingCycle === 'monthly' ? translate('::Public.products.billingcycle.month') : translate('::Public.products.billingcycle.year')} @@ -117,10 +117,10 @@ export const BillingControls: React.FC = ({ @@ -78,7 +78,7 @@ export const Cart: React.FC = ({
    {cartState.items.length === 0 ? ( -
    +

    {translate('::Public.cart.empty.title')}

    {translate('::Public.cart.empty.subtitle')}

    @@ -88,10 +88,10 @@ export const Cart: React.FC = ({ {cartState.items.map((item: BasketItem, index: number) => (
    -

    +

    {translate('::' + item.product.name)}

    -
    +
    {item.product.isQuantityBased && item.quantity > 1 && ( - {item.quantity}x - + {item.quantity}x - )} {item.billingCycle === 'monthly' ? translate('::Public.products.billingcycle.monthly') @@ -113,7 +113,7 @@ export const Cart: React.FC = ({ ? translate('::Public.products.billingcycle.yearly') : translate('::Public.products.billingcycle.monthly')} {cartState.globalPeriod > 1 && item.product.isQuantityBased && ( - + ({cartState.globalPeriod}{' '} {item.billingCycle === 'monthly' ? translate('::Public.products.billingcycle.month') @@ -127,14 +127,14 @@ export const Cart: React.FC = ({
    - {item.quantity} + {item.quantity} @@ -152,9 +152,9 @@ export const Cart: React.FC = ({
    {cartState.items.length > 0 && ( -
    +
    - + {translate('::App.Listform.ListformField.Total')} diff --git a/ui/src/components/orders/OrderSuccess.tsx b/ui/src/components/orders/OrderSuccess.tsx index fe7ee71..eeed79a 100644 --- a/ui/src/components/orders/OrderSuccess.tsx +++ b/ui/src/components/orders/OrderSuccess.tsx @@ -15,24 +15,24 @@ export const OrderSuccess: React.FC = ({ orderId, onBackToSho return (
    -
    +
    -

    +

    {translate('::Public.order.success.title')}

    -

    +

    {translate('::Public.order.success.number')}{' '} #{orderId}

    -
    -

    +
    +

    {translate('::Public.order.success.nextSteps')}

    -
      +
      • • {translate('::Public.order.success.step1')}
      • • {translate('::Public.order.success.step2')}
      • • {translate('::Public.order.success.step3')}
      • @@ -42,7 +42,7 @@ export const OrderSuccess: React.FC = ({ orderId, onBackToSho
        ) } + diff --git a/ui/src/components/orders/ProductCard.tsx b/ui/src/components/orders/ProductCard.tsx index 1c3e9eb..359ac70 100644 --- a/ui/src/components/orders/ProductCard.tsx +++ b/ui/src/components/orders/ProductCard.tsx @@ -89,7 +89,7 @@ export const ProductCard: React.FC = ({ } return ( -
        +
        {product.imageUrl && (
        = ({
        -

        {translate('::' + product.name)}

        +

        {translate('::' + product.name)}

        -

        {translate('::' + product.description)}

        +

        {translate('::' + product.description)}

        {/* Quantity and Yearly Savings above price */}
        {product.isQuantityBased && (
        - + {translate('::Public.products.quantity')}
        - {quantity} + {quantity} @@ -148,14 +148,14 @@ export const ProductCard: React.FC = ({ {/* Bottom section with consistent height */}
        -
        +
        {formatPrice(getCurrentPrice())} - {getUnitText()} + {getUnitText()}
        {globalPeriod > 1 && (
        {translate('::App.Listform.ListformField.Total')} {formatPrice(getTotalPrice())} - {getPeriodText()} + {getPeriodText()}
        )}
        @@ -170,7 +170,7 @@ export const ProductCard: React.FC = ({ disabled={isDisabled} className={`w-full font-medium py-3 px-4 rounded-lg transition-colors duration-200 transform ${ isDisabled - ? 'bg-gray-400 text-gray-700 cursor-not-allowed' + ? 'bg-gray-400 text-gray-700 cursor-not-allowed dark:bg-gray-700 dark:text-gray-400' : 'bg-blue-600 hover:bg-blue-700 text-white hover:scale-[1.02] active:scale-[0.98]' }`} > diff --git a/ui/src/components/orders/ProductCatalog.tsx b/ui/src/components/orders/ProductCatalog.tsx index be464d1..51db000 100644 --- a/ui/src/components/orders/ProductCatalog.tsx +++ b/ui/src/components/orders/ProductCatalog.tsx @@ -88,10 +88,10 @@ export const ProductCatalog: React.FC = ({ return (