Compare commits
7 Commits
main
...
d17e917534
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d17e917534 | ||
|
|
3ea10e9c78 | ||
|
|
34c5eb0a23 | ||
|
|
0d642dee8e | ||
|
|
1f9de6eda0 | ||
|
|
85d91ce55e | ||
|
|
46c2a4be52 |
49
GIZLILIK_POLITIKASI.md
Normal file
49
GIZLILIK_POLITIKASI.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 🛡️ hMarket - Gizlilik Politikası
|
||||||
|
|
||||||
|
**Son Güncelleme:** 22 Şubat 2026
|
||||||
|
|
||||||
|
Bu gizlilik politikası, **hMarket** (https://hmarket.mustafaozkaya.tr/) mobil uygulaması ve web platformu tarafından toplanan bilgilerin nasıl kullanıldığını, saklandığını ve korunduğunu açıklamaktadır. hMarket, kullanıcılarına akıllı alışveriş listeleri oluşturma, yönetme ve paylaşma hizmeti sunan bir PWA (Progressive Web App) uygulamasıdır.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. Toplanan Veriler
|
||||||
|
hMarket'i kullandığınızda aşağıdaki kategorilerde veriler toplanabilir:
|
||||||
|
|
||||||
|
* **Hesap Bilgileri:** Kayıt sırasında sağladığınız ad, soyad ve e-posta adresi.
|
||||||
|
* **Sosyal Giriş Bilgileri:** Google ile giriş yaptığınızda, Google profilinizden sağlanan isim, e-posta ve profil fotoğrafı.
|
||||||
|
* **İçerik Verileri:** Oluşturduğunuz alışveriş listeleri, eklediğiniz ürünler, miktarlar ve paylaştığınız kişilerin bilgileri.
|
||||||
|
* **Teknik Veriler:** IP adresi, cihaz türü, tarayıcı bilgileri ve uygulama içi kullanım istatistikleri.
|
||||||
|
* **Bildirim Verileri:** Push bildirimleri gönderebilmek amacıyla Firebase üzerinden alınan cihaz jetonları (tokens).
|
||||||
|
|
||||||
|
### 2. Verilerin Kullanım Amacı
|
||||||
|
Toplanan veriler aşağıdaki süreçler için kullanılır:
|
||||||
|
* Alışveriş listelerinin cihazlar arasında senkronize edilmesi.
|
||||||
|
* Listelerin diğer kullanıcılarla paylaşılarak ortak çalışma imkanı sunulması.
|
||||||
|
* Listelerde yapılan değişiklikler hakkında gerçek zamanlı bildirim gönderilmesi.
|
||||||
|
* Kullanıcı deneyiminin iyileştirilmesi ve teknik hataların giderilmesi.
|
||||||
|
|
||||||
|
### 3. Verilerin Paylaşımı ve Saklanması
|
||||||
|
Kişisel verileriniz, yasal zorunluluklar veya hizmetin teknik gereklilikleri (Örn: Bildirimler için Firebase, Giriş için Google) dışında **üçüncü şahıslarla paylaşılmaz.** Verileriniz güvenli veritabanlarında şifrelenmiş olarak saklanır.
|
||||||
|
|
||||||
|
### 4. Çerezler ve Yerel Depolama
|
||||||
|
hMarket, oturumunuzu açık tutmak ve tercihlerinizi hatırlamak için tarayıcınızın **Local Storage** ve **Cookies** (çerezler) özelliklerini kullanır.
|
||||||
|
|
||||||
|
### 5. Kullanıcı Hakları (KVKK / GDPR)
|
||||||
|
Kullanıcılar olarak her zaman şu haklara sahipsiniz:
|
||||||
|
* Hangi verilerinizin tutulduğunu sorgulama.
|
||||||
|
* Yanlış verilerin düzeltilmesini isteme.
|
||||||
|
* Hesabınızı ve tüm listelerinizi kalıcı olarak silme.
|
||||||
|
* Pazarlama amaçlı veri kullanımına itiraz etme.
|
||||||
|
|
||||||
|
### 6. Hesap ve Veri Silme
|
||||||
|
Kullanıcılar, uygulama içindeki profil ayarlarından hesaplarını ve hesaplarına bağlı tüm verileri istedikleri an silebilirler. Silinen veriler geri getirilemez şekilde sistemden kaldırılır.
|
||||||
|
|
||||||
|
### 7. İletişim
|
||||||
|
Gizlilik politikası hakkındaki sorularınız ve veri talepleriniz için:
|
||||||
|
* **Geliştirici:** Mustafa ÖZKAYA
|
||||||
|
* **Web:** https://www.mustafaozkaya.tr/
|
||||||
|
* **E-posta:** [E-posta adresinizi buraya ekleyin]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Bu belge hMarket uygulamasının modern gizlilik standartlarına uyumu için hOLOlu tarafından hazırlanmıştır.*
|
||||||
33
KULLANIM_SARTLARI.md
Normal file
33
KULLANIM_SARTLARI.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# 📜 hMarket - Kullanım Şartları
|
||||||
|
|
||||||
|
**Son Güncelleme:** 22 Şubat 2026
|
||||||
|
|
||||||
|
hMarket uygulamasını kullanarak aşağıdaki şartları kabul etmiş sayılırsınız. Lütfen bu metni dikkatlice okuyunuz.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. Hizmet Tanımı
|
||||||
|
hMarket, Mustafa ÖZKAYA tarafından geliştirilen, kullanıcıların kişisel veya paylaşımlı alışveriş listeleri oluşturmasına olanak tanıyan bir yazılım hizmetidir.
|
||||||
|
|
||||||
|
### 2. Kullanım Koşulları
|
||||||
|
* Uygulamayı kullanmak için geçerli bir e-posta adresi veya Google hesabı ile kayıt olmanız gerekebilir.
|
||||||
|
* Hesap bilgilerinizin güvenliğinden tamamen siz sorumlusunuz.
|
||||||
|
* Uygulama, kişisel kullanım için tasarlanmıştır; sistemin işleyişini bozacak saldırı veya tersine mühendislik çabaları yasaktır.
|
||||||
|
|
||||||
|
### 3. Fikri Mülkiyet Hakları
|
||||||
|
hMarket yazılımı, tasarımı, logosu ve tüm kod içeriği Mustafa ÖZKAYA'ya aittir. İzinsiz kopyalanamaz veya dağıtılamaz.
|
||||||
|
|
||||||
|
### 4. Sorumluluk Reddi
|
||||||
|
* hMarket, "olduğu gibi" sunulur. Teknik arızalar, veri kayıpları veya sistem kesintilerinden kaynaklanabilecek dolaylı zararlardan geliştirici sorumlu tutulamaz.
|
||||||
|
* Kullanıcıların listelerine eklediği içeriklerin doğruluğu ve yasal sorumluluğu kullanıcıya aittir.
|
||||||
|
|
||||||
|
### 5. Değişiklikler
|
||||||
|
Geliştirici, hizmet şartlarını önceden haber vermeksizin güncelleme hakkını saklı tutar. Güncel şartlar uygulama içinden veya web sitesinden takip edilebilir.
|
||||||
|
|
||||||
|
### 6. İletişim
|
||||||
|
Hizmet şartları hakkında sorularınız için:
|
||||||
|
* **Geliştirici:** Mustafa ÖZKAYA
|
||||||
|
* **E-posta:** [E-posta adresinizi buraya ekleyin]
|
||||||
|
|
||||||
|
---
|
||||||
|
*hMarket hizmet kalitesini ve kullanıcı güvenliğini ön planda tutar.*
|
||||||
1
backend/package-lock.json
generated
1
backend/package-lock.json
generated
@@ -3075,7 +3075,6 @@
|
|||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|||||||
BIN
backend/prisma/dev.db
Normal file
BIN
backend/prisma/dev.db
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
// HMarket Veritabanı Şeması
|
// HMarket Veritabanı Şeması
|
||||||
// MariaDB için Prisma ORM konfigürasyonu
|
// MySQL için Prisma ORM konfigürasyonu
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
@@ -128,7 +128,7 @@ model Product {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
description String?
|
description String?
|
||||||
barcode String? @unique
|
barcode String? // barkod opsiyonel
|
||||||
brand String?
|
brand String?
|
||||||
unit String? // Ürün varsayılan birimi
|
unit String? // Ürün varsayılan birimi
|
||||||
categoryId String?
|
categoryId String?
|
||||||
@@ -153,7 +153,7 @@ model ListItem {
|
|||||||
customName String? // Ürün yoksa manuel isim
|
customName String? // Ürün yoksa manuel isim
|
||||||
quantity Float @default(1)
|
quantity Float @default(1)
|
||||||
unit String @default("adet") // "kg", "lt", "adet", vb.
|
unit String @default("adet") // "kg", "lt", "adet", vb.
|
||||||
price Decimal? @db.Decimal(10, 2)
|
price Decimal? // SQLite: Decimal stored as String
|
||||||
note String?
|
note String?
|
||||||
isPurchased Boolean @default(false)
|
isPurchased Boolean @default(false)
|
||||||
purchasedAt DateTime?
|
purchasedAt DateTime?
|
||||||
@@ -174,7 +174,7 @@ model ListItem {
|
|||||||
model PriceHistory {
|
model PriceHistory {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
productId String
|
productId String
|
||||||
price Decimal @db.Decimal(10, 2)
|
price Decimal // SQLite: Decimal stored as String
|
||||||
store String? // Mağaza adı
|
store String? // Mağaza adı
|
||||||
location String? // Konum bilgisi
|
location String? // Konum bilgisi
|
||||||
source String @default("user") // "user", "api", "scraping"
|
source String @default("user") // "user", "api", "scraping"
|
||||||
@@ -193,7 +193,7 @@ model Notification {
|
|||||||
title String
|
title String
|
||||||
message String
|
message String
|
||||||
type String // "list_shared", "item_added", "item_purchased", "price_alert"
|
type String // "list_shared", "item_added", "item_purchased", "price_alert"
|
||||||
data Json? // Ek veri (JSON format)
|
data String? // Ek veri (JSON format - SQLite String olarak saklanır)
|
||||||
isRead Boolean @default(false)
|
isRead Boolean @default(false)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ model Activity {
|
|||||||
listId String
|
listId String
|
||||||
userId String
|
userId String
|
||||||
action String // "item_added", "item_removed", "item_updated", "item_purchased"
|
action String // "item_added", "item_removed", "item_updated", "item_purchased"
|
||||||
details Json? // Aktivite detayları
|
details String? // Aktivite detayları (JSON - SQLite String olarak saklanır)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
// İlişkiler
|
// İlişkiler
|
||||||
|
|||||||
@@ -1,389 +1,139 @@
|
|||||||
const { PrismaClient } = require('@prisma/client');
|
import { PrismaClient } from '@prisma/client'
|
||||||
const bcrypt = require('bcryptjs');
|
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('🌱 Veritabanı seed işlemi başlatılıyor...');
|
console.log('Örnek veriler ekleniyor...')
|
||||||
|
|
||||||
// Admin kullanıcısı oluştur
|
// Kullanıcılar
|
||||||
const hashedPassword = await bcrypt.hash('admin123', 12);
|
const user1 = await prisma.user.create({
|
||||||
|
data: {
|
||||||
const adminUser = await prisma.user.upsert({
|
email: 'mustafa@example.com',
|
||||||
where: { email: 'admin@hmarket.com' },
|
username: 'mustafa',
|
||||||
update: {},
|
firstName: 'Mustafa',
|
||||||
create: {
|
lastName: 'ÖZKAYA',
|
||||||
email: 'admin@hmarket.com',
|
password: '$2a$10$dummy',
|
||||||
username: 'admin',
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=mustafa',
|
||||||
firstName: 'Admin',
|
}
|
||||||
lastName: 'User',
|
})
|
||||||
password: hashedPassword,
|
|
||||||
isAdmin: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('✅ Admin kullanıcısı oluşturuldu:', adminUser.email);
|
const user2 = await prisma.user.create({
|
||||||
|
data: {
|
||||||
// Test kullanıcıları oluştur
|
email: 'ahmet@example.com',
|
||||||
const testUsers = [
|
|
||||||
{
|
|
||||||
email: 'ahmet@test.com',
|
|
||||||
username: 'ahmet',
|
username: 'ahmet',
|
||||||
firstName: 'Ahmet',
|
firstName: 'Ahmet',
|
||||||
lastName: 'Yılmaz',
|
lastName: 'Yılmaz',
|
||||||
password: await bcrypt.hash('test123', 12),
|
password: '$2a$10$dummy',
|
||||||
},
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ahmet',
|
||||||
{
|
}
|
||||||
email: 'ayse@test.com',
|
})
|
||||||
|
|
||||||
|
const user3 = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email: 'ayse@example.com',
|
||||||
username: 'ayse',
|
username: 'ayse',
|
||||||
firstName: 'Ayşe',
|
firstName: 'Ayşe',
|
||||||
lastName: 'Kaya',
|
lastName: 'Kaya',
|
||||||
password: await bcrypt.hash('test123', 12),
|
password: '$2a$10$dummy',
|
||||||
},
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ayse',
|
||||||
{
|
|
||||||
email: 'mehmet@test.com',
|
|
||||||
username: 'mehmet',
|
|
||||||
firstName: 'Mehmet',
|
|
||||||
lastName: 'Demir',
|
|
||||||
password: await bcrypt.hash('test123', 12),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const userData of testUsers) {
|
|
||||||
const user = await prisma.user.upsert({
|
|
||||||
where: { email: userData.email },
|
|
||||||
update: {},
|
|
||||||
create: userData,
|
|
||||||
});
|
|
||||||
console.log('✅ Test kullanıcısı oluşturuldu:', user.email);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kategoriler oluştur
|
|
||||||
const categories = [
|
|
||||||
{ name: 'Meyve & Sebze', description: 'Taze meyve ve sebzeler', icon: '🥕', color: '#4CAF50' },
|
|
||||||
{ name: 'Et & Tavuk', description: 'Kırmızı et, beyaz et ve şarküteri ürünleri', icon: '🥩', color: '#F44336' },
|
|
||||||
{ name: 'Süt Ürünleri', description: 'Süt, peynir, yoğurt ve diğer süt ürünleri', icon: '🥛', color: '#2196F3' },
|
|
||||||
{ name: 'Fırın & Pastane', description: 'Ekmek, pasta ve unlu mamuller', icon: '🍞', color: '#FF9800' },
|
|
||||||
{ name: 'Atıştırmalık', description: 'Çikolata, bisküvi ve atıştırmalık ürünler', icon: '🍿', color: '#9C27B0' },
|
|
||||||
{ name: 'İçecek', description: 'Alkolsüz içecekler ve sıcak içecekler', icon: '🥤', color: '#00BCD4' },
|
|
||||||
{ name: 'Temizlik', description: 'Ev temizlik ürünleri ve deterjanlar', icon: '🧽', color: '#607D8B' },
|
|
||||||
{ name: 'Kişisel Bakım', description: 'Kişisel hijyen ve bakım ürünleri', icon: '🧴', color: '#E91E63' },
|
|
||||||
{ name: 'Bebek', description: 'Bebek bakım ürünleri ve mama', icon: '🍼', color: '#FFEB3B' },
|
|
||||||
{ name: 'Dondurulmuş', description: 'Dondurulmuş gıda ürünleri', icon: '🧊', color: '#3F51B5' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const categoryData of categories) {
|
|
||||||
const category = await prisma.category.upsert({
|
|
||||||
where: { name: categoryData.name },
|
|
||||||
update: {},
|
|
||||||
create: categoryData,
|
|
||||||
});
|
|
||||||
console.log('✅ Kategori oluşturuldu:', category.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Örnek ürünler oluştur
|
|
||||||
const products = [
|
|
||||||
// Meyve & Sebze
|
|
||||||
{ name: 'Elma', categoryName: 'Meyve & Sebze', barcode: '1234567890123', averagePrice: 12.50 },
|
|
||||||
{ name: 'Muz', categoryName: 'Meyve & Sebze', barcode: '1234567890124', averagePrice: 18.00 },
|
|
||||||
{ name: 'Domates', categoryName: 'Meyve & Sebze', barcode: '1234567890125', averagePrice: 8.75 },
|
|
||||||
{ name: 'Salatalık', categoryName: 'Meyve & Sebze', barcode: '1234567890126', averagePrice: 6.50 },
|
|
||||||
{ name: 'Soğan', categoryName: 'Meyve & Sebze', barcode: '1234567890127', averagePrice: 4.25 },
|
|
||||||
{ name: 'Patates', categoryName: 'Meyve & Sebze', barcode: '1234567890137', averagePrice: 5.75 },
|
|
||||||
{ name: 'Havuç', categoryName: 'Meyve & Sebze', barcode: '1234567890138', averagePrice: 7.50 },
|
|
||||||
{ name: 'Biber', categoryName: 'Meyve & Sebze', barcode: '1234567890139', averagePrice: 15.00 },
|
|
||||||
{ name: 'Portakal', categoryName: 'Meyve & Sebze', barcode: '1234567890140', averagePrice: 10.00 },
|
|
||||||
{ name: 'Limon', categoryName: 'Meyve & Sebze', barcode: '1234567890141', averagePrice: 8.00 },
|
|
||||||
|
|
||||||
// Süt Ürünleri
|
|
||||||
{ name: 'Süt 1L', categoryName: 'Süt Ürünleri', barcode: '1234567890128', averagePrice: 8.75 },
|
|
||||||
{ name: 'Yoğurt 500g', categoryName: 'Süt Ürünleri', barcode: '1234567890129', averagePrice: 12.50 },
|
|
||||||
{ name: 'Beyaz Peynir', categoryName: 'Süt Ürünleri', barcode: '1234567890130', averagePrice: 45.00 },
|
|
||||||
{ name: 'Kaşar Peyniri', categoryName: 'Süt Ürünleri', barcode: '1234567890131', averagePrice: 65.00 },
|
|
||||||
{ name: 'Tereyağı', categoryName: 'Süt Ürünleri', barcode: '1234567890142', averagePrice: 35.00 },
|
|
||||||
{ name: 'Yumurta 30\'lu', categoryName: 'Süt Ürünleri', barcode: '1234567890143', averagePrice: 85.00 },
|
|
||||||
{ name: 'Krema', categoryName: 'Süt Ürünleri', barcode: '1234567890144', averagePrice: 15.50 },
|
|
||||||
|
|
||||||
// Fırın & Pastane
|
|
||||||
{ name: 'Ekmek', categoryName: 'Fırın & Pastane', barcode: '1234567890132', averagePrice: 4.50 },
|
|
||||||
{ name: 'Simit', categoryName: 'Fırın & Pastane', barcode: '1234567890133', averagePrice: 2.50 },
|
|
||||||
{ name: 'Pide', categoryName: 'Fırın & Pastane', barcode: '1234567890145', averagePrice: 8.00 },
|
|
||||||
{ name: 'Çörek', categoryName: 'Fırın & Pastane', barcode: '1234567890146', averagePrice: 6.50 },
|
|
||||||
{ name: 'Kek', categoryName: 'Fırın & Pastane', barcode: '1234567890147', averagePrice: 25.00 },
|
|
||||||
|
|
||||||
// İçecek
|
|
||||||
{ name: 'Su 1.5L', categoryName: 'İçecek', barcode: '1234567890134', averagePrice: 2.50 },
|
|
||||||
{ name: 'Çay', categoryName: 'İçecek', barcode: '1234567890135', averagePrice: 35.00 },
|
|
||||||
{ name: 'Kahve', categoryName: 'İçecek', barcode: '1234567890136', averagePrice: 85.00 },
|
|
||||||
{ name: 'Meyve Suyu', categoryName: 'İçecek', barcode: '1234567890148', averagePrice: 12.50 },
|
|
||||||
{ name: 'Kola', categoryName: 'İçecek', barcode: '1234567890149', averagePrice: 8.75 },
|
|
||||||
{ name: 'Ayran', categoryName: 'İçecek', barcode: '1234567890150', averagePrice: 4.50 },
|
|
||||||
|
|
||||||
// Et & Tavuk
|
|
||||||
{ name: 'Tavuk But', categoryName: 'Et & Tavuk', barcode: '1234567890151', averagePrice: 45.00 },
|
|
||||||
{ name: 'Dana Kıyma', categoryName: 'Et & Tavuk', barcode: '1234567890152', averagePrice: 120.00 },
|
|
||||||
{ name: 'Köfte', categoryName: 'Et & Tavuk', barcode: '1234567890153', averagePrice: 85.00 },
|
|
||||||
{ name: 'Sosis', categoryName: 'Et & Tavuk', barcode: '1234567890154', averagePrice: 25.00 },
|
|
||||||
|
|
||||||
// Temizlik
|
|
||||||
{ name: 'Deterjan', categoryName: 'Temizlik', barcode: '1234567890155', averagePrice: 45.00 },
|
|
||||||
{ name: 'Sabun', categoryName: 'Temizlik', barcode: '1234567890156', averagePrice: 8.50 },
|
|
||||||
{ name: 'Şampuan', categoryName: 'Temizlik', barcode: '1234567890157', averagePrice: 35.00 },
|
|
||||||
{ name: 'Diş Macunu', categoryName: 'Kişisel Bakım', barcode: '1234567890158', averagePrice: 18.50 },
|
|
||||||
|
|
||||||
// Atıştırmalık
|
|
||||||
{ name: 'Çikolata', categoryName: 'Atıştırmalık', barcode: '1234567890159', averagePrice: 12.50 },
|
|
||||||
{ name: 'Bisküvi', categoryName: 'Atıştırmalık', barcode: '1234567890160', averagePrice: 8.75 },
|
|
||||||
{ name: 'Cips', categoryName: 'Atıştırmalık', barcode: '1234567890161', averagePrice: 6.50 },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const productData of products) {
|
|
||||||
const category = await prisma.category.findUnique({
|
|
||||||
where: { name: productData.categoryName }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (category) {
|
|
||||||
const product = await prisma.product.upsert({
|
|
||||||
where: { barcode: productData.barcode },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
name: productData.name,
|
|
||||||
barcode: productData.barcode,
|
|
||||||
categoryId: category.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log('✅ Ürün oluşturuldu:', product.name);
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
// Örnek alışveriş listeleri oluştur
|
console.log('✅ Kullanıcılar oluşturuldu')
|
||||||
const ahmetUser = await prisma.user.findUnique({
|
|
||||||
where: { email: 'ahmet@test.com' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const ayseUser = await prisma.user.findUnique({
|
// Kategoriler
|
||||||
where: { email: 'ayse@test.com' }
|
const cat1 = await prisma.category.create({ data: { name: 'Sebze & Meyve', icon: '🥬', color: '#4CAF50' } })
|
||||||
});
|
const cat2 = await prisma.category.create({ data: { name: 'Et & Tavuk', icon: '🥩', color: '#F44336' } })
|
||||||
|
const cat3 = await prisma.category.create({ data: { name: 'Süt & Süt Ürünleri', icon: '🥛', color: '#2196F3' } })
|
||||||
|
const cat4 = await prisma.category.create({ data: { name: 'Ekmek & Unlu Mamüller', icon: '🍞', color: '#FF9800' } })
|
||||||
|
const cat5 = await prisma.category.create({ data: { name: 'İçecekler', icon: '🥤', color: '#9C27B0' } })
|
||||||
|
const cat6 = await prisma.category.create({ data: { name: 'Temizlik', icon: '🧹', color: '#607D8B' } })
|
||||||
|
const cat7 = await prisma.category.create({ data: { name: 'Atıştırmalık', icon: '🍪', color: '#795548' } })
|
||||||
|
const cat8 = await prisma.category.create({ data: { name: 'Dondurma', icon: '🍦', color: '#E91E63' } })
|
||||||
|
|
||||||
const mehmetUser = await prisma.user.findUnique({
|
console.log('✅ Kategoriler oluşturuldu')
|
||||||
where: { email: 'mehmet@test.com' }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ahmet için alışveriş listeleri
|
// Ürünler
|
||||||
if (ahmetUser) {
|
const products = await Promise.all([
|
||||||
const shoppingLists = [
|
prisma.product.create({ data: { name: 'Domates', categoryId: cat1.id, unit: 'kg' } }),
|
||||||
{
|
prisma.product.create({ data: { name: 'Soğan', categoryId: cat1.id, unit: 'kg' } }),
|
||||||
name: 'Haftalık Alışveriş',
|
prisma.product.create({ data: { name: 'Salatalık', categoryId: cat1.id, unit: 'adet' } }),
|
||||||
description: 'Bu haftanın market alışverişi',
|
prisma.product.create({ data: { name: 'Tavuk Göğsü', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
color: '#4CAF50',
|
prisma.product.create({ data: { name: 'Kıyma', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
items: [
|
prisma.product.create({ data: { name: 'Kırmızı Et', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
{ productName: 'Elma', quantity: 2, unit: 'kg', price: 15.50 },
|
prisma.product.create({ data: { name: 'Süt', categoryId: cat3.id, unit: 'L' } }),
|
||||||
{ productName: 'Süt 1L', quantity: 1, unit: 'adet', price: 8.75 },
|
prisma.product.create({ data: { name: 'Yoğurt', categoryId: cat3.id, unit: 'adet' } }),
|
||||||
{ customName: 'Deterjan', quantity: 1, unit: 'adet', price: 25.00, note: 'Çamaşır deterjanı' },
|
prisma.product.create({ data: { name: 'Ekmek', categoryId: cat4.id, unit: 'adet' } }),
|
||||||
{ productName: 'Ekmek', quantity: 2, unit: 'adet', price: 9.00 },
|
prisma.product.create({ data: { name: 'Cola', categoryId: cat5.id, unit: 'adet' } }),
|
||||||
{ productName: 'Yumurta 30\'lu', quantity: 1, unit: 'adet', price: 85.00 },
|
prisma.product.create({ data: { name: 'Bulaşık Deterjanı', categoryId: cat6.id, unit: 'adet' } }),
|
||||||
]
|
prisma.product.create({ data: { name: 'Baklava', categoryId: cat7.id, unit: 'kg' } }),
|
||||||
},
|
prisma.product.create({ data: { name: 'Dondurma', categoryId: cat8.id, unit: 'L' } }),
|
||||||
{
|
])
|
||||||
name: 'Kahvaltı Malzemeleri',
|
|
||||||
description: 'Kahvaltı için gerekli ürünler',
|
|
||||||
color: '#FF9800',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Ekmek', quantity: 2, unit: 'adet', price: 9.00 },
|
|
||||||
{ productName: 'Beyaz Peynir', quantity: 1, unit: 'kg', price: 45.00 },
|
|
||||||
{ productName: 'Tereyağı', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
{ productName: 'Domates', quantity: 1, unit: 'kg', price: 8.75 },
|
|
||||||
{ productName: 'Salatalık', quantity: 2, unit: 'adet', price: 13.00 },
|
|
||||||
{ productName: 'Çay', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const listData of shoppingLists) {
|
console.log('✅ Ürünler oluşturuldu')
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
|
||||||
data: {
|
|
||||||
name: listData.name,
|
|
||||||
description: listData.description,
|
|
||||||
color: listData.color,
|
|
||||||
ownerId: ahmetUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of listData.items) {
|
// Market Listeleri
|
||||||
let productId = null;
|
const list1 = await prisma.shoppingList.create({
|
||||||
|
data: {
|
||||||
if (itemData.productName) {
|
name: 'Haftalık Market',
|
||||||
const product = await prisma.product.findFirst({
|
description: 'Bu hafta alınacaklar',
|
||||||
where: { name: itemData.productName }
|
color: '#4CAF50',
|
||||||
});
|
ownerId: user1.id,
|
||||||
if (product) {
|
|
||||||
productId = product.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.listItem.create({
|
|
||||||
data: {
|
|
||||||
listId: shoppingList.id,
|
|
||||||
productId: productId,
|
|
||||||
customName: itemData.customName,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
note: itemData.note,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
// Ayşe için alışveriş listeleri
|
// Listeye üye ekle
|
||||||
if (ayseUser) {
|
await prisma.listMember.create({
|
||||||
const ayseShoppingLists = [
|
data: {
|
||||||
{
|
userId: user2.id,
|
||||||
name: 'Parti Alışverişi',
|
listId: list1.id,
|
||||||
description: 'Doğum günü partisi için',
|
role: 'admin'
|
||||||
color: '#E91E63',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Kek', quantity: 1, unit: 'adet', price: 25.00 },
|
|
||||||
{ productName: 'Çikolata', quantity: 5, unit: 'adet', price: 62.50 },
|
|
||||||
{ productName: 'Bisküvi', quantity: 3, unit: 'paket', price: 26.25 },
|
|
||||||
{ productName: 'Kola', quantity: 6, unit: 'adet', price: 52.50 },
|
|
||||||
{ productName: 'Meyve Suyu', quantity: 4, unit: 'adet', price: 50.00 },
|
|
||||||
{ customName: 'Parti Süsleri', quantity: 1, unit: 'set', price: 45.00 },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Temizlik Malzemeleri',
|
|
||||||
description: 'Ev temizliği için gerekli ürünler',
|
|
||||||
color: '#607D8B',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Deterjan', quantity: 2, unit: 'adet', price: 90.00 },
|
|
||||||
{ productName: 'Sabun', quantity: 3, unit: 'adet', price: 25.50 },
|
|
||||||
{ productName: 'Şampuan', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
{ customName: 'Cam Temizleyici', quantity: 1, unit: 'adet', price: 18.50 },
|
|
||||||
{ customName: 'Yer Bezi', quantity: 2, unit: 'adet', price: 15.00 },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const listData of ayseShoppingLists) {
|
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
|
||||||
data: {
|
|
||||||
name: listData.name,
|
|
||||||
description: listData.description,
|
|
||||||
color: listData.color,
|
|
||||||
ownerId: ayseUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of listData.items) {
|
|
||||||
let productId = null;
|
|
||||||
|
|
||||||
if (itemData.productName) {
|
|
||||||
const product = await prisma.product.findFirst({
|
|
||||||
where: { name: itemData.productName }
|
|
||||||
});
|
|
||||||
if (product) {
|
|
||||||
productId = product.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.listItem.create({
|
|
||||||
data: {
|
|
||||||
listId: shoppingList.id,
|
|
||||||
productId: productId,
|
|
||||||
customName: itemData.customName,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
// Mehmet için alışveriş listesi
|
// Liste Öğeleri (productId kullan)
|
||||||
if (mehmetUser) {
|
await prisma.listItem.create({ data: { productId: products[0].id, quantity: 2, unit: 'kg', listId: list1.id } }) // Domates
|
||||||
const mehmetShoppingList = {
|
await prisma.listItem.create({ data: { productId: products[1].id, quantity: 1, unit: 'kg', listId: list1.id } }) // Soğan
|
||||||
name: 'Et ve Protein',
|
await prisma.listItem.create({ data: { productId: products[2].id, quantity: 3, unit: 'adet', listId: list1.id, isPurchased: true } }) // Salatalık
|
||||||
description: 'Protein ihtiyacı için et ürünleri',
|
await prisma.listItem.create({ data: { productId: products[3].id, quantity: 1, unit: 'kg', listId: list1.id } }) // Tavuk
|
||||||
color: '#F44336',
|
await prisma.listItem.create({ data: { productId: products[4].id, quantity: 0.5, unit: 'kg', listId: list1.id } }) // Kıyma
|
||||||
items: [
|
await prisma.listItem.create({ data: { productId: products[6].id, quantity: 2, unit: 'L', listId: list1.id, isPurchased: true } }) // Süt
|
||||||
{ productName: 'Tavuk But', quantity: 2, unit: 'kg', price: 90.00 },
|
await prisma.listItem.create({ data: { productId: products[7].id, quantity: 4, unit: 'adet', listId: list1.id } }) // Yoğurt
|
||||||
{ productName: 'Dana Kıyma', quantity: 1, unit: 'kg', price: 120.00 },
|
await prisma.listItem.create({ data: { productId: products[8].id, quantity: 2, unit: 'adet', listId: list1.id } }) // Ekmek
|
||||||
{ productName: 'Köfte', quantity: 1, unit: 'kg', price: 85.00 },
|
await prisma.listItem.create({ data: { productId: products[9].id, quantity: 6, unit: 'adet', listId: list1.id } }) // Cola
|
||||||
{ productName: 'Sosis', quantity: 2, unit: 'paket', price: 50.00 },
|
await prisma.listItem.create({ data: { productId: products[10].id, quantity: 1, unit: 'adet', listId: list1.id, isPurchased: true } }) // Deterjan
|
||||||
{ productName: 'Yumurta 30\'lu', quantity: 1, unit: 'adet', price: 85.00 },
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
console.log('✅ İlk liste oluşturuldu')
|
||||||
data: {
|
|
||||||
name: mehmetShoppingList.name,
|
|
||||||
description: mehmetShoppingList.description,
|
|
||||||
color: mehmetShoppingList.color,
|
|
||||||
ownerId: mehmetUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of mehmetShoppingList.items) {
|
// İkinci liste
|
||||||
let productId = null;
|
const list2 = await prisma.shoppingList.create({
|
||||||
|
data: {
|
||||||
if (itemData.productName) {
|
name: 'Bayram Alışverişi',
|
||||||
const product = await prisma.product.findFirst({
|
description: 'Bayram için gerekli malzemeler',
|
||||||
where: { name: itemData.productName }
|
color: '#E91E63',
|
||||||
});
|
ownerId: user1.id,
|
||||||
if (product) {
|
|
||||||
productId = product.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.listItem.create({
|
|
||||||
data: {
|
|
||||||
listId: shoppingList.id,
|
|
||||||
productId: productId,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
await prisma.listItem.create({ data: { productId: products[5].id, quantity: 2, unit: 'kg', listId: list2.id } }) // Kırmızı Et
|
||||||
}
|
await prisma.listItem.create({ data: { productId: products[11].id, quantity: 1, unit: 'kg', listId: list2.id } }) // Baklava
|
||||||
|
await prisma.listItem.create({ data: { productId: products[12].id, quantity: 2, unit: 'L', listId: list2.id } }) // Dondurma
|
||||||
|
|
||||||
console.log('✅ Tüm örnek alışveriş listeleri oluşturuldu');
|
console.log('✅ İkinci liste oluşturuldu')
|
||||||
|
|
||||||
// Sistem ayarları
|
console.log('\n🎉 Örnek veriler başarıyla eklendi!')
|
||||||
const settings = [
|
console.log(` - 3 kullanıcı`)
|
||||||
{ key: 'app_name', value: 'HMarket', type: 'string' },
|
console.log(` - 8 kategori`)
|
||||||
{ key: 'app_version', value: '1.0.0', type: 'string' },
|
console.log(` - ${await prisma.product.count()} ürün`)
|
||||||
{ key: 'max_list_members', value: '10', type: 'number' },
|
console.log(` - 2 liste`)
|
||||||
{ key: 'enable_notifications', value: 'true', type: 'boolean' },
|
console.log(` - 13 liste öğesi`)
|
||||||
{ key: 'default_currency', value: 'TL', type: 'string' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const settingData of settings) {
|
|
||||||
await prisma.setting.upsert({
|
|
||||||
where: { key: settingData.key },
|
|
||||||
update: { value: settingData.value },
|
|
||||||
create: settingData,
|
|
||||||
});
|
|
||||||
console.log('✅ Ayar oluşturuldu:', settingData.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('🎉 Seed işlemi tamamlandı!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('❌ Seed işlemi sırasında hata:', e);
|
console.error(e)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect()
|
||||||
});
|
})
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const GoogleStrategy = require('passport-google-oauth20').Strategy;
|
|
||||||
const { PrismaClient } = require('@prisma/client');
|
const { PrismaClient } = require('@prisma/client');
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
@@ -32,67 +31,71 @@ passport.deserializeUser(async (id, done) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Google OAuth Strategy
|
// Google OAuth Strategy - Sadece credentials varsa yükle
|
||||||
passport.use(new GoogleStrategy({
|
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
|
||||||
clientID: process.env.GOOGLE_CLIENT_ID,
|
const GoogleStrategy = require('passport-google-oauth20').Strategy;
|
||||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
||||||
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
|
passport.use(new GoogleStrategy({
|
||||||
}, async (accessToken, refreshToken, profile, done) => {
|
clientID: process.env.GOOGLE_CLIENT_ID,
|
||||||
try {
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||||
// Önce Google ID ile kullanıcı ara
|
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
|
||||||
let user = await prisma.user.findUnique({
|
}, async (accessToken, refreshToken, profile, done) => {
|
||||||
where: { googleId: profile.id }
|
try {
|
||||||
});
|
// Önce Google ID ile kullanıcı ara
|
||||||
|
let user = await prisma.user.findUnique({
|
||||||
if (user) {
|
where: { googleId: profile.id }
|
||||||
// Kullanıcı zaten var, son giriş tarihini güncelle
|
|
||||||
user = await prisma.user.update({
|
|
||||||
where: { id: user.id },
|
|
||||||
data: { lastLoginAt: new Date() }
|
|
||||||
});
|
});
|
||||||
return done(null, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email ile kullanıcı ara (mevcut hesap varsa bağla)
|
if (user) {
|
||||||
user = await prisma.user.findUnique({
|
// Kullanıcı zaten var, son giriş tarihini güncelle
|
||||||
where: { email: profile.emails[0].value }
|
user = await prisma.user.update({
|
||||||
});
|
where: { id: user.id },
|
||||||
|
data: { lastLoginAt: new Date() }
|
||||||
|
});
|
||||||
|
return done(null, user);
|
||||||
|
}
|
||||||
|
|
||||||
if (user) {
|
// Email ile kullanıcı ara (mevcut hesap varsa bağla)
|
||||||
// Mevcut hesabı Google ile bağla
|
user = await prisma.user.findUnique({
|
||||||
user = await prisma.user.update({
|
where: { email: profile.emails[0].value }
|
||||||
where: { id: user.id },
|
});
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
// Mevcut hesabı Google ile bağla
|
||||||
|
user = await prisma.user.update({
|
||||||
|
where: { id: user.id },
|
||||||
|
data: {
|
||||||
|
googleId: profile.id,
|
||||||
|
authProvider: 'google',
|
||||||
|
avatar: profile.photos[0]?.value || user.avatar,
|
||||||
|
lastLoginAt: new Date()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return done(null, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yeni kullanıcı oluştur
|
||||||
|
const username = profile.emails[0].value.split('@')[0] + '_' + Math.random().toString(36).substr(2, 4);
|
||||||
|
|
||||||
|
user = await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
|
email: profile.emails[0].value,
|
||||||
|
username: username,
|
||||||
|
firstName: profile.name.givenName || '',
|
||||||
|
lastName: profile.name.familyName || '',
|
||||||
googleId: profile.id,
|
googleId: profile.id,
|
||||||
authProvider: 'google',
|
authProvider: 'google',
|
||||||
avatar: profile.photos[0]?.value || user.avatar,
|
avatar: profile.photos[0]?.value,
|
||||||
lastLoginAt: new Date()
|
lastLoginAt: new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return done(null, user);
|
return done(null, user);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Google OAuth Error:', error);
|
||||||
|
return done(error, null);
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
// Yeni kullanıcı oluştur
|
}
|
||||||
const username = profile.emails[0].value.split('@')[0] + '_' + Math.random().toString(36).substr(2, 4);
|
|
||||||
|
|
||||||
user = await prisma.user.create({
|
|
||||||
data: {
|
|
||||||
email: profile.emails[0].value,
|
|
||||||
username: username,
|
|
||||||
firstName: profile.name.givenName || '',
|
|
||||||
lastName: profile.name.familyName || '',
|
|
||||||
googleId: profile.id,
|
|
||||||
authProvider: 'google',
|
|
||||||
avatar: profile.photos[0]?.value,
|
|
||||||
lastLoginAt: new Date()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return done(null, user);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Google OAuth Error:', error);
|
|
||||||
return done(error, null);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
module.exports = passport;
|
module.exports = passport;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { PrismaClient } = require('@prisma/client');
|
|
||||||
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
|
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
|
||||||
const { asyncHandler } = require('../middleware/errorHandler');
|
const { asyncHandler } = require('../middleware/errorHandler');
|
||||||
const {
|
const {
|
||||||
@@ -15,7 +14,6 @@ const { successResponse, errorResponse, calculatePagination, createPaginationMet
|
|||||||
const notificationService = require('../services/notificationService');
|
const notificationService = require('../services/notificationService');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Liste öğelerini getir
|
* Liste öğelerini getir
|
||||||
@@ -68,8 +66,8 @@ router.get('/:listId',
|
|||||||
|
|
||||||
// Toplam sayı ve öğeleri getir
|
// Toplam sayı ve öğeleri getir
|
||||||
const [total, items] = await Promise.all([
|
const [total, items] = await Promise.all([
|
||||||
prisma.listItem.count({ where }),
|
req.prisma.listItem.count({ where }),
|
||||||
prisma.listItem.findMany({
|
req.prisma.listItem.findMany({
|
||||||
where,
|
where,
|
||||||
skip,
|
skip,
|
||||||
take,
|
take,
|
||||||
@@ -116,7 +114,7 @@ router.get('/:listId/:itemId',
|
|||||||
|
|
||||||
const { listId, itemId } = req.params;
|
const { listId, itemId } = req.params;
|
||||||
|
|
||||||
const item = await prisma.listItem.findFirst({
|
const item = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -179,7 +177,7 @@ router.post('/:listId',
|
|||||||
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
|
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
|
||||||
let product = null;
|
let product = null;
|
||||||
if (productId) {
|
if (productId) {
|
||||||
product = await prisma.product.findUnique({
|
product = await req.prisma.product.findUnique({
|
||||||
where: { id: productId }
|
where: { id: productId }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,7 +187,7 @@ router.post('/:listId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Aynı öğenin listede zaten var olup olmadığını kontrol et
|
// Aynı öğenin listede zaten var olup olmadığını kontrol et
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
listId,
|
listId,
|
||||||
OR: [
|
OR: [
|
||||||
@@ -204,7 +202,7 @@ router.post('/:listId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Yeni öğe oluştur
|
// Yeni öğe oluştur
|
||||||
const newItem = await prisma.listItem.create({
|
const newItem = await req.prisma.listItem.create({
|
||||||
data: {
|
data: {
|
||||||
customName: productId ? product.name : name,
|
customName: productId ? product.name : name,
|
||||||
quantity,
|
quantity,
|
||||||
@@ -226,26 +224,26 @@ router.post('/:listId',
|
|||||||
// Ürün kullanım sayısını artır (Product modelinde usageCount alanı yok, bu özellik kaldırıldı)
|
// Ürün kullanım sayısını artır (Product modelinde usageCount alanı yok, bu özellik kaldırıldı)
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur (geçici olarak devre dışı)
|
||||||
await prisma.activity.create({
|
// await req.prisma.activity.create({
|
||||||
data: {
|
// data: {
|
||||||
action: 'item_added',
|
// action: 'item_added',
|
||||||
details: {
|
// details: {
|
||||||
itemId: newItem.id,
|
// itemId: newItem.id,
|
||||||
itemName: newItem.customName || newItem.product?.name || 'Öğe',
|
// itemName: newItem.customName || newItem.product?.name || 'Öğe',
|
||||||
userName: `${req.user.firstName} ${req.user.lastName}`
|
// userName: `${req.user.firstName} ${req.user.lastName}`
|
||||||
},
|
// },
|
||||||
userId,
|
// userId,
|
||||||
listId
|
// listId
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Liste üyelerine bildirim gönder (geçici olarak devre dışı - notifyListMembers fonksiyonu mevcut değil)
|
// Liste üyelerine bildirim gönder (geçici olarak devre dışı)
|
||||||
// await notificationService.notifyListMembers(
|
// await notificationService.notifyListMembers(
|
||||||
// listId,
|
// listId,
|
||||||
// userId,
|
// userId,
|
||||||
@@ -254,14 +252,14 @@ router.post('/:listId',
|
|||||||
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
|
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// Socket.IO ile gerçek zamanlı güncelleme
|
// Socket.IO ile gerçek zamanlı güncelleme (geçici olarak devre dışı)
|
||||||
const io = req.app.get('io');
|
// const io = req.app.get('io');
|
||||||
if (io) {
|
// if (io) {
|
||||||
io.to(`list_${listId}`).emit('itemAdded', {
|
// io.to(`list_${listId}`).emit('itemAdded', {
|
||||||
item: newItem,
|
// item: newItem,
|
||||||
addedBy: req.user
|
// addedBy: req.user
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Priority değerini string'e çevir
|
// Priority değerini string'e çevir
|
||||||
const newItemWithStringPriority = {
|
const newItemWithStringPriority = {
|
||||||
@@ -321,7 +319,7 @@ router.put('/:listId/:itemId',
|
|||||||
|
|
||||||
// Öğenin var olduğunu kontrol et
|
// Öğenin var olduğunu kontrol et
|
||||||
console.log('🔍 Öğe aranıyor:', { itemId, listId });
|
console.log('🔍 Öğe aranıyor:', { itemId, listId });
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -364,7 +362,7 @@ router.put('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğeyi güncelle
|
// Öğeyi güncelle
|
||||||
const updatedItem = await prisma.listItem.update({
|
const updatedItem = await req.prisma.listItem.update({
|
||||||
where: { id: itemId },
|
where: { id: itemId },
|
||||||
data: updateData,
|
data: updateData,
|
||||||
include: {
|
include: {
|
||||||
@@ -378,7 +376,7 @@ router.put('/:listId/:itemId',
|
|||||||
|
|
||||||
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
|
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
|
||||||
if (price && existingItem.productId && isPurchased) {
|
if (price && existingItem.productId && isPurchased) {
|
||||||
await prisma.priceHistory.create({
|
await req.prisma.priceHistory.create({
|
||||||
data: {
|
data: {
|
||||||
price: price,
|
price: price,
|
||||||
productId: existingItem.productId,
|
productId: existingItem.productId,
|
||||||
@@ -389,7 +387,7 @@ router.put('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
@@ -402,7 +400,7 @@ router.put('/:listId/:itemId',
|
|||||||
: `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesinin satın alma durumunu iptal etti`;
|
: `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesinin satın alma durumunu iptal etti`;
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.activity.create({
|
await req.prisma.activity.create({
|
||||||
data: {
|
data: {
|
||||||
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
|
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
|
||||||
details: {
|
details: {
|
||||||
@@ -467,7 +465,7 @@ router.delete('/:listId/:itemId',
|
|||||||
const userId = req.user.id;
|
const userId = req.user.id;
|
||||||
|
|
||||||
// Öğenin var olduğunu kontrol et
|
// Öğenin var olduğunu kontrol et
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -479,19 +477,19 @@ router.delete('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğeyi sil
|
// Öğeyi sil
|
||||||
await prisma.listItem.delete({
|
await req.prisma.listItem.delete({
|
||||||
where: { id: itemId }
|
where: { id: itemId }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur (Prisma şemasına uygun)
|
// Aktivite kaydı oluştur (Prisma şemasına uygun)
|
||||||
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
|
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
|
||||||
await prisma.activity.create({
|
await req.prisma.activity.create({
|
||||||
data: {
|
data: {
|
||||||
action: 'ITEM_REMOVED',
|
action: 'ITEM_REMOVED',
|
||||||
details: {
|
details: {
|
||||||
@@ -551,7 +549,7 @@ router.patch('/:listId/bulk',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğelerin var olduğunu kontrol et
|
// Öğelerin var olduğunu kontrol et
|
||||||
const existingItems = await prisma.listItem.findMany({
|
const existingItems = await req.prisma.listItem.findMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
@@ -593,14 +591,14 @@ router.patch('/:listId/bulk',
|
|||||||
|
|
||||||
// Toplu güncelleme veya silme
|
// Toplu güncelleme veya silme
|
||||||
if (action === 'delete') {
|
if (action === 'delete') {
|
||||||
await prisma.listItem.deleteMany({
|
await req.prisma.listItem.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await prisma.listItem.updateMany({
|
await req.prisma.listItem.updateMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
@@ -610,13 +608,13 @@ router.patch('/:listId/bulk',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur
|
||||||
await prisma.activity.create({
|
await req.prisma.activity.create({
|
||||||
data: {
|
data: {
|
||||||
type: activityType,
|
type: activityType,
|
||||||
description: activityDescription,
|
description: activityDescription,
|
||||||
|
|||||||
@@ -198,23 +198,25 @@ router.post('/', authenticateToken, [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur (geçici olarak devre dışı)
|
||||||
await req.prisma.activity.create({
|
// await req.prisma.activity.create({
|
||||||
data: {
|
// data: {
|
||||||
listId: list.id,
|
// listId: list.id,
|
||||||
userId: req.user.id,
|
// userId: req.user.id,
|
||||||
action: 'list_created',
|
// action: 'list_created',
|
||||||
details: {
|
// details: {
|
||||||
listName: list.name
|
// listName: list.name
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Socket.IO ile gerçek zamanlı bildirim gönder
|
// Socket.IO ile gerçek zamanlı bildirim gönder (geçici olarak devre dışı)
|
||||||
req.io.emit('list_created', {
|
// if (req.io) {
|
||||||
list: { ...list, userRole: 'owner' },
|
// req.io.emit('list_created', {
|
||||||
user: req.user
|
// list: { ...list, userRole: 'owner' },
|
||||||
});
|
// user: req.user
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ process.on('SIGINT', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sunucuyu başlat
|
// Sunucuyu başlat
|
||||||
const PORT = process.env.PORT || 5000;
|
const PORT = process.env.PORT || 7001;
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`🚀 Server ${PORT} portunda çalışıyor - port 7001`);
|
console.log(`🚀 Server ${PORT} portunda çalışıyor - port 7001`);
|
||||||
|
|||||||
@@ -9,6 +9,16 @@ class NotificationService {
|
|||||||
|
|
||||||
initializeFirebase() {
|
initializeFirebase() {
|
||||||
try {
|
try {
|
||||||
|
// Firebase credentials kontrolü
|
||||||
|
const hasCredentials = process.env.FIREBASE_PROJECT_ID &&
|
||||||
|
process.env.FIREBASE_PRIVATE_KEY &&
|
||||||
|
process.env.FIREBASE_CLIENT_EMAIL;
|
||||||
|
|
||||||
|
if (!hasCredentials) {
|
||||||
|
console.log('⚠️ Firebase credentials not configured. Push notifications disabled.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!admin.apps.length) {
|
if (!admin.apps.length) {
|
||||||
const serviceAccount = {
|
const serviceAccount = {
|
||||||
type: process.env.FIREBASE_TYPE,
|
type: process.env.FIREBASE_TYPE,
|
||||||
@@ -27,10 +37,11 @@ class NotificationService {
|
|||||||
credential: admin.credential.cert(serviceAccount)
|
credential: admin.credential.cert(serviceAccount)
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Firebase Admin SDK initialized successfully');
|
console.log('✅ Firebase Admin SDK initialized successfully');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Firebase initialization error:', error);
|
console.error('Firebase initialization error:', error.message);
|
||||||
|
console.warn('Push notifications will be disabled.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,20 @@ function getDatabaseName(databaseUrl) {
|
|||||||
|
|
||||||
async function setupUtf8mb4(prisma) {
|
async function setupUtf8mb4(prisma) {
|
||||||
const databaseUrl = process.env.DATABASE_URL || '';
|
const databaseUrl = process.env.DATABASE_URL || '';
|
||||||
|
|
||||||
|
// SQLite için bu fonksiyonu atla
|
||||||
|
if (databaseUrl.includes('sqlite') || databaseUrl.includes('.db')) {
|
||||||
|
console.log('ℹ️ SQLite kullanılıyor. UTF8MB4 kurulumu atlandı.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dbName = getDatabaseName(databaseUrl);
|
const dbName = getDatabaseName(databaseUrl);
|
||||||
if (!dbName) {
|
if (!dbName) {
|
||||||
console.warn('⚠️ DATABASE_URL bulunamadı veya veritabanı adı çözümlenemedi. UTF8MB4 kurulumu atlandı.');
|
console.warn('⚠️ DATABASE_URL bulunamadı veya veritabanı adı çözümlenemedi. UTF8MB4 kurulumu atlandı.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try altering database charset/collation
|
// Only run for MySQL/MariaDB
|
||||||
try {
|
try {
|
||||||
await prisma.$executeRawUnsafe(`ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
|
await prisma.$executeRawUnsafe(`ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
|
||||||
console.log('✅ Veritabanı varsayılan karakter seti/collation utf8mb4 olarak ayarlandı.');
|
console.log('✅ Veritabanı varsayılan karakter seti/collation utf8mb4 olarak ayarlandı.');
|
||||||
@@ -30,7 +37,6 @@ async function setupUtf8mb4(prisma) {
|
|||||||
console.warn('⚠️ Veritabanı charset ayarlanırken hata oluştu:', err?.message || err);
|
console.warn('⚠️ Veritabanı charset ayarlanırken hata oluştu:', err?.message || err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try converting categories table
|
|
||||||
try {
|
try {
|
||||||
await prisma.$executeRawUnsafe('ALTER TABLE `categories` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
|
await prisma.$executeRawUnsafe('ALTER TABLE `categories` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
|
||||||
console.log('✅ `categories` tablosu utf8mb4 olarak dönüştürüldü.');
|
console.log('✅ `categories` tablosu utf8mb4 olarak dönüştürüldü.');
|
||||||
|
|||||||
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
@@ -15610,19 +15610,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss/node_modules/yaml": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"yaml": "bin.mjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="hMarket - Akıllı Alışveriş Listesi ve Fiyat Takibi"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>hMarket - Akıllı Alışveriş Listesi</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"short_name": "React App",
|
"short_name": "hMarket",
|
||||||
"name": "Create React App Sample",
|
"name": "hMarket - Akıllı Alışveriş Listesi",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const Navbar: React.FC = () => {
|
|||||||
<Box sx={{ p: 2, display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ p: 2, display: 'flex', alignItems: 'center' }}>
|
||||||
<ShoppingCart sx={{ mr: 1, color: 'primary.main' }} />
|
<ShoppingCart sx={{ mr: 1, color: 'primary.main' }} />
|
||||||
<Typography variant="h6" color="primary.main" fontWeight="bold">
|
<Typography variant="h6" color="primary.main" fontWeight="bold">
|
||||||
HMarket
|
hMarket
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -139,7 +139,7 @@ const Navbar: React.FC = () => {
|
|||||||
<Box sx={{ display: 'flex', alignItems: 'center', flexGrow: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', flexGrow: 1 }}>
|
||||||
<ShoppingCart sx={{ mr: 1 }} />
|
<ShoppingCart sx={{ mr: 1 }} />
|
||||||
<Typography variant="h6" component="div" fontWeight="bold">
|
<Typography variant="h6" component="div" fontWeight="bold">
|
||||||
HMarket
|
hMarket
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
@@ -188,7 +188,7 @@ const Navbar: React.FC = () => {
|
|||||||
sx={{ cursor: 'pointer' }}
|
sx={{ cursor: 'pointer' }}
|
||||||
onClick={() => navigate('/dashboard')}
|
onClick={() => navigate('/dashboard')}
|
||||||
>
|
>
|
||||||
HMarket
|
hMarket
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ const LoginPage: React.FC = () => {
|
|||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||||
<ShoppingCart sx={{ fontSize: 40, color: 'primary.main', mr: 1 }} />
|
<ShoppingCart sx={{ fontSize: 40, color: 'primary.main', mr: 1 }} />
|
||||||
<Typography component="h1" variant="h4" color="primary.main" fontWeight="bold">
|
<Typography component="h1" variant="h4" color="primary.main" fontWeight="bold">
|
||||||
HMarket
|
hMarket
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -244,13 +244,34 @@ const LoginPage: React.FC = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box sx={{ textAlign: 'center', mt: 3, pt: 2, borderTop: '1px solid rgba(0,0,0,0.05)', display: 'flex', justifyContent: 'center', gap: 2 }}>
|
||||||
|
<Link
|
||||||
|
href="https://www.mustafaozkaya.tr/hmarket-kullanim-sartlari/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
variant="caption"
|
||||||
|
sx={{ textDecoration: 'none', color: 'text.secondary' }}
|
||||||
|
>
|
||||||
|
Kullanım Şartları
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="https://www.mustafaozkaya.tr/hmarket-gizlilik-politikasi/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
variant="caption"
|
||||||
|
sx={{ textDecoration: 'none', color: 'text.secondary' }}
|
||||||
|
>
|
||||||
|
Gizlilik Politikası
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Features */}
|
{/* Features */}
|
||||||
<Box sx={{ mt: 4, textAlign: 'center' }}>
|
<Box sx={{ mt: 4, textAlign: 'center' }}>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
Neden HMarket?
|
Neden hMarket?
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', gap: 4, mt: 2 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'center', gap: 4, mt: 2 }}>
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ const RegisterPage: React.FC = () => {
|
|||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||||
<ShoppingCart sx={{ fontSize: 40, color: 'primary.main', mr: 1 }} />
|
<ShoppingCart sx={{ fontSize: 40, color: 'primary.main', mr: 1 }} />
|
||||||
<Typography component="h1" variant="h4" color="primary.main" fontWeight="bold">
|
<Typography component="h1" variant="h4" color="primary.main" fontWeight="bold">
|
||||||
HMarket
|
hMarket
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -352,14 +352,25 @@ const RegisterPage: React.FC = () => {
|
|||||||
{/* Terms */}
|
{/* Terms */}
|
||||||
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
By creating an account, you agree to our{' '}
|
Hesap oluşturarak,{' '}
|
||||||
<Link href="#" sx={{ textDecoration: 'none' }}>
|
<Link
|
||||||
Terms of Service
|
href="https://www.mustafaozkaya.tr/hmarket-kullanim-sartlari/"
|
||||||
</Link>{' '}
|
target="_blank"
|
||||||
and{' '}
|
rel="noopener"
|
||||||
<Link href="#" sx={{ textDecoration: 'none' }}>
|
sx={{ textDecoration: 'none' }}
|
||||||
Privacy Policy
|
>
|
||||||
|
Kullanım Şartları
|
||||||
</Link>
|
</Link>
|
||||||
|
{' '}ve{' '}
|
||||||
|
<Link
|
||||||
|
href="https://www.mustafaozkaya.tr/hmarket-gizlilik-politikasi/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
sx={{ textDecoration: 'none' }}
|
||||||
|
>
|
||||||
|
Gizlilik Politikası
|
||||||
|
</Link>
|
||||||
|
'nı kabul etmiş olursunuz.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
Avatar,
|
Avatar,
|
||||||
LinearProgress,
|
LinearProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
Link,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Add,
|
Add,
|
||||||
@@ -324,6 +325,33 @@ const DashboardPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Box sx={{ mt: 8, pt: 4, borderTop: '1px solid rgba(0,0,0,0.05)', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<Link
|
||||||
|
href="https://www.mustafaozkaya.tr/hmarket-kullanim-sartlari/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
variant="body2"
|
||||||
|
sx={{ textDecoration: 'none', color: 'text.secondary' }}
|
||||||
|
>
|
||||||
|
Kullanım Şartları
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="https://www.mustafaozkaya.tr/hmarket-gizlilik-politikasi/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
variant="body2"
|
||||||
|
sx={{ textDecoration: 'none', color: 'text.secondary' }}
|
||||||
|
>
|
||||||
|
Gizlilik Politikası
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="caption" display="block" sx={{ mt: 1, color: 'text.disabled' }}>
|
||||||
|
© 2026 hMarket - Mustafa ÖZKAYA
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{"email":"admin@hmarket.com","password":"admin123"}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"login": "ahmet@test.com",
|
|
||||||
"password": "test123"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user