Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
10ec2d1739
|
|||
|
b71c6b5c02
|
|||
|
839eee0746
|
|||
|
8f32c77f7e
|
|||
|
2db526d949
|
|||
|
17046735da
|
|||
|
5cd80fe27e
|
|||
|
d2e9f80c30
|
|||
|
43d04c7f93
|
|||
|
1cbd74b6a5
|
|||
|
d88f1b6e0b
|
|||
|
73a1c521d5
|
|||
|
9050bbc5cf
|
|||
|
2cce8d89ca
|
|||
|
41435aa4fc
|
|||
|
7dc8a49a8d
|
|||
|
816d115fbc
|
|||
|
715f3a9d96
|
|||
|
3febc68b4e
|
|||
|
f06967708d
|
|||
|
f79435d64f
|
|||
|
04ac930900
|
|||
|
d8193f8174
|
|||
|
d08b0d6f90
|
|||
|
3b027e4a39
|
|||
|
49f57b5c10
|
|||
|
ac75a64ec8
|
|||
|
0e195ac079
|
|||
|
6358e7e72d
|
|||
|
97be5d1b93
|
|||
|
c42a9dacf0
|
|||
|
4b929bb272
|
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "Backend"]
|
||||||
|
path = Backend
|
||||||
|
url = https://git.kska.io/notkshitij/SkycrateBackend.git
|
||||||
@@ -5,10 +5,11 @@
|
|||||||
## Work distribution
|
## Work distribution
|
||||||
|
|
||||||
- Design: Kapil
|
- Design: Kapil
|
||||||
- Frontend: Shivani, Shriniwas, Ombase, Tejas, Sonali, Dinesh
|
- Frontend: Ombase, Shriniwas, Dinesh, Lalit, Shivani, Pracheta, Vaibhavi
|
||||||
- Backend: Vedang, Lalit
|
- Backend: Vedang, Sonali, Lalit
|
||||||
- DBMS: Lalit
|
- DBMS: Lalit
|
||||||
- HDFS: Sonali, Prajakta, Poonam
|
- HDFS: Sonali, Prajakta, Poonam
|
||||||
|
- Deployment: Kshitij, Sahil
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Submodule
+1
Submodule Backend added at e1da884fbb
+1
-1
@@ -1 +1 @@
|
|||||||
VITE_API_URL=http://192.168.29.61:8081
|
VITE_API_URL=http://localhost:8080
|
||||||
|
|||||||
@@ -23,3 +23,7 @@ package-lock.json
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
#########
|
||||||
|
|
||||||
|
.vite/
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
## FRONTEND ##
|
||||||
|
|
||||||
|
# Base image
|
||||||
|
FROM node:22
|
||||||
|
|
||||||
|
# Metadata
|
||||||
|
LABEL maintainer="kshitijka"
|
||||||
|
LABEL version=1.0
|
||||||
|
LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem."
|
||||||
|
|
||||||
|
# Update & upgrade & rm
|
||||||
|
RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/* && npm install -g http-server
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN useradd -s /bin/bash skycrateFront
|
||||||
|
|
||||||
|
# Create work dir
|
||||||
|
RUN mkdir /app
|
||||||
|
RUN chown -R skycrateFront:skycrateFront /app
|
||||||
|
COPY ./dist/ /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Switch user
|
||||||
|
USER skycrateFront
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["http-server", "/app"]
|
||||||
+15
-17
@@ -10,30 +10,28 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reduxjs/toolkit": "^2.6.0",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
"@tailwindcss/vite": "^4.0.9",
|
"@tailwindcss/vite": "^4.1.11",
|
||||||
"axios": "^1.8.4",
|
"i18next": "^25.2.1",
|
||||||
"lucide-react": "^0.476.0",
|
"lucide-react": "^0.476.0",
|
||||||
"react": "^19.0.0",
|
"prop-types": "^15.8.1",
|
||||||
"react-dom": "^19.0.0",
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
|
"react-i18next": "^15.5.3",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^7.2.0"
|
"react-router-dom": "^7.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.21.0",
|
"@eslint/js": "^9.21.0",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"eslint": "^9.29.0",
|
||||||
"autoprefixer": "^10.4.20",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint": "^9.21.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react": "^7.37.4",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"eslint-plugin-react-hooks": "^5.0.0",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
|
||||||
"globals": "^15.15.0",
|
"globals": "^15.15.0",
|
||||||
"postcss": "^8.5.3",
|
"vite": "^6.3.5"
|
||||||
"tailwindcss": "^4.0.9",
|
|
||||||
"vite": "^6.2.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
|
import LanguageSwitcher from './components/LanguageSwitcher'; // Language switcher dropdown menu
|
||||||
import Login from "./pages/Authentication/Login";
|
import Login from "./pages/Authentication/Login";
|
||||||
import SignUp from "./pages/Authentication/SignUp";
|
import SignUp from "./pages/Authentication/SignUp";
|
||||||
import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage";
|
import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage";
|
||||||
@@ -9,6 +10,7 @@ import NotFoundPage from "./pages/UserPages/NotFoundPage";
|
|||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
|
<LanguageSwitcher />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<DrivethruLandingPage />} />
|
<Route path="/" element={<DrivethruLandingPage />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8080";
|
const API_URL = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
const FileTable = ({ initialPath }) => {
|
const FileTable = ({ initialPath }) => {
|
||||||
// Read username dynamically to avoid stale null on first load
|
// Read username dynamically to avoid stale null on first load
|
||||||
|
|||||||
@@ -8,15 +8,17 @@ import {
|
|||||||
Phone,
|
Phone,
|
||||||
MapPin,
|
MapPin,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
|
|
||||||
//Currently storing user email in localstorage
|
//Currently storing user email in localstorage
|
||||||
const handleSubscribe = () => {
|
const handleSubscribe = () => {
|
||||||
if (email.trim() !== "") {
|
if (email.trim() !== "") {
|
||||||
localStorage.setItem("subscribedEmail", email);
|
localStorage.setItem("subscribedEmail", email);
|
||||||
alert("You have successfully subscribed!");
|
alert(t("subscribe_success"));
|
||||||
setEmail("");
|
setEmail("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -42,10 +44,10 @@ const Footer = () => {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-2xl font-bold text-white">Skycrate</h3>
|
<h3 className="text-2xl font-bold text-white">{t("footer_brand")}</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-white/90">
|
<p className="text-white/90">
|
||||||
Your secure cloud storage solution for all your digital needs.
|
{t("footer_tagline")}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex space-x-4">
|
<div className="flex space-x-4">
|
||||||
<a
|
<a
|
||||||
@@ -81,14 +83,14 @@ const Footer = () => {
|
|||||||
|
|
||||||
{/* Quick Links */}
|
{/* Quick Links */}
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold text-white mb-4">Quick Links</h4>
|
<h4 className="font-semibold text-white mb-4">{t("footer_quick_links")}</h4>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="#about"
|
href="#about"
|
||||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
About Us
|
{t("footer_about_us")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -96,7 +98,7 @@ const Footer = () => {
|
|||||||
href="#features"
|
href="#features"
|
||||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
Features
|
{t("footer_features")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -104,7 +106,7 @@ const Footer = () => {
|
|||||||
href="#howItWorks"
|
href="#howItWorks"
|
||||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
How It Works
|
{t("footer_how_it_works")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -112,43 +114,42 @@ const Footer = () => {
|
|||||||
|
|
||||||
{/* Contact Info */}
|
{/* Contact Info */}
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold text-white mb-4">Contact</h4>
|
<h4 className="font-semibold text-white mb-4">{t("footer_contact")}</h4>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||||
<Mail className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
<Mail className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||||
support@drivethru.com
|
{t("footer_email")}
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||||
<Phone className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
<Phone className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||||
+91 3628206234
|
{t("footer_phone")}
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||||
<MapPin className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
<MapPin className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||||
123 Cloud Street, Digital City
|
{t("footer_address")}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Newsletter */}
|
{/* Newsletter */}
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold text-white mb-4">Stay Updated</h4>
|
<h4 className="font-semibold text-white mb-4">{t("footer_newsletter_title")}</h4>
|
||||||
<p className="text-white/90 mb-4">
|
<p className="text-white/90 mb-4">
|
||||||
Get exclusive tips, updates on new features, and special offers
|
{t("footer_newsletter_desc")}
|
||||||
directly in your inbox.
|
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="Enter your email"
|
placeholder={t("footer_newsletter_placeholder")}
|
||||||
className="w-full px-4 py-2 rounded-md bg-white/10 border border-white/20 text-white placeholder:text-white/50 focus:bg-white/20 transition-all duration-200 outline-none focus:ring-2 focus:ring-white/30"
|
className="w-full px-4 py-2 rounded-md bg-white/10 border border-white/20 text-white placeholder:text-white/50 focus:bg-white/20 transition-all duration-200 outline-none focus:ring-2 focus:ring-white/30"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={handleSubscribe}
|
onClick={handleSubscribe}
|
||||||
className="w-full px-4 py-2 rounded-md bg-white text-blue-600 font-medium hover:bg-opacity-90 transition-all duration-200 transform hover:scale-105"
|
className="w-full px-4 py-2 rounded-md bg-white text-blue-600 font-medium hover:bg-opacity-90 transition-all duration-200 transform hover:scale-105"
|
||||||
>
|
>
|
||||||
Subscribe to Newsletter
|
{t("footer_newsletter_button")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -158,25 +159,25 @@ const Footer = () => {
|
|||||||
|
|
||||||
{/* Bottom Section */}
|
{/* Bottom Section */}
|
||||||
<div className="flex flex-col md:flex-row justify-between items-center text-white/90 text-sm">
|
<div className="flex flex-col md:flex-row justify-between items-center text-white/90 text-sm">
|
||||||
<p>© {new Date().getFullYear()} Skycrate. All rights reserved.</p>
|
<p>© {new Date().getFullYear()} {t("footer_brand")}. {t("footer_rights")}</p>
|
||||||
<div className="flex gap-4 mt-4 md:mt-0">
|
<div className="flex gap-4 mt-4 md:mt-0">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
Privacy Policy
|
{t("footer_privacy_policy")}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
Terms of Service
|
{t("footer_terms_of_service")}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||||
>
|
>
|
||||||
Cookie Policy
|
{t("footer_cookie_policy")}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ code: 'en', label: 'English' },
|
||||||
|
{ code: 'hi', label: 'Hindi (हिंदी)' },
|
||||||
|
{ code: 'mr', label: 'Marathi (मराठी)' },
|
||||||
|
{ code: 'fr', label: 'French (Français)' },
|
||||||
|
// Add more languages as needed
|
||||||
|
];
|
||||||
|
|
||||||
|
function LanguageSwitcher() {
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '1rem',
|
||||||
|
right: '1rem',
|
||||||
|
zIndex: 1000,
|
||||||
|
background: 'rgba(255,255,255,0.95)',
|
||||||
|
borderRadius: '4px',
|
||||||
|
padding: '0.25em 0.5em',
|
||||||
|
boxShadow: '0 2px 8px rgba(0,0,0,0.05)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
value={i18n.language}
|
||||||
|
onChange={e => i18n.changeLanguage(e.target.value)}
|
||||||
|
style={{
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
borderRadius: '4px',
|
||||||
|
padding: '0.25em 2em 0.25em 0.5em', // More right padding for arrow
|
||||||
|
minWidth: '100px',
|
||||||
|
appearance: 'auto', // Use browser default arrow
|
||||||
|
background: '#fff',
|
||||||
|
}}
|
||||||
|
|
||||||
|
aria-label="Select language"
|
||||||
|
>
|
||||||
|
{languages.map(lang => (
|
||||||
|
<option key={lang.code} value={lang.code}>
|
||||||
|
{lang.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LanguageSwitcher;
|
||||||
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
const navigate = useNavigate(); // Hook for programmatic navigation
|
const navigate = useNavigate(); // Hook for programmatic navigation
|
||||||
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||||
const menuRef = useRef();
|
const menuRef = useRef();
|
||||||
|
|
||||||
// Show loading toast and perform logout
|
// Show loading toast and perform logout
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
const loadingToast = toast.loading("Logging out...");
|
const loadingToast = toast.loading(t("sidebar_logging_out"));
|
||||||
|
|
||||||
// Simulate a delay (for example, network request)
|
// Simulate a delay (for example, network request)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -23,7 +25,7 @@ const Sidebar = () => {
|
|||||||
|
|
||||||
// Show success toast after logout
|
// Show success toast after logout
|
||||||
toast.update(loadingToast, {
|
toast.update(loadingToast, {
|
||||||
render: "Logged out successfully!",
|
render: t("sidebar_logged_out"),
|
||||||
type: "success",
|
type: "success",
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
autoClose: 2000,
|
autoClose: 2000,
|
||||||
@@ -55,7 +57,7 @@ const Sidebar = () => {
|
|||||||
type="button"
|
type="button"
|
||||||
className="inline-flex items-center p-2 text-lg text-white rounded-lg sm:hidden hover:bg-[#37A0EA] focus:outline-none"
|
className="inline-flex items-center p-2 text-lg text-white rounded-lg sm:hidden hover:bg-[#37A0EA] focus:outline-none"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open sidebar</span>
|
<span className="sr-only">{t("sidebar_open_sidebar")}</span>
|
||||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path
|
||||||
clipRule="evenodd"
|
clipRule="evenodd"
|
||||||
@@ -67,7 +69,7 @@ const Sidebar = () => {
|
|||||||
<Link to="/" className="flex ms-2 md:me-24">
|
<Link to="/" className="flex ms-2 md:me-24">
|
||||||
<img src="./image.png" className="h-8 me-3" alt="Skycrate Logo" />
|
<img src="./image.png" className="h-8 me-3" alt="Skycrate Logo" />
|
||||||
<span className="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap">
|
<span className="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap">
|
||||||
Skycrate
|
{t("sidebar_brand")}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,11 +86,11 @@ const Sidebar = () => {
|
|||||||
onClick={() => setUserMenuOpen((o) => !o)}
|
onClick={() => setUserMenuOpen((o) => !o)}
|
||||||
className="flex text-lg bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300"
|
className="flex text-lg bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open user menu</span>
|
<span className="sr-only">{t("sidebar_open_user_menu")}</span>
|
||||||
<img
|
<img
|
||||||
className="w-8 h-8 rounded-full"
|
className="w-8 h-8 rounded-full"
|
||||||
src="https://flowbite.com/docs/images/people/profile-picture-5.jpg"
|
src="https://flowbite.com/docs/images/people/profile-picture-5.jpg"
|
||||||
alt="User Photo"
|
alt={t("sidebar_user_photo")}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -109,7 +111,7 @@ const Sidebar = () => {
|
|||||||
className="w-full text-left px-4 py-2 text-lg text-white hover:bg-[#37A0EA]"
|
className="w-full text-left px-4 py-2 text-lg text-white hover:bg-[#37A0EA]"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
>
|
>
|
||||||
Log out
|
{t("sidebar_logout")}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -139,7 +141,7 @@ const Sidebar = () => {
|
|||||||
>
|
>
|
||||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.62L12 2 9.19 8.62 2 9.24l5.46 4.73L5.82 21z" />
|
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.62L12 2 9.19 8.62 2 9.24l5.46 4.73L5.82 21z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span className="ms-3">Starred</span>
|
<span className="ms-3">{t("sidebar_starred")}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
{/* ...additional sidebar items... */}
|
{/* ...additional sidebar items... */}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
|
||||||
|
import en from './locales/en.json';
|
||||||
|
import hi from './locales/hi.json';
|
||||||
|
import mr from './locales/mr.json';
|
||||||
|
import fr from './locales/fr.json';
|
||||||
|
// import more languages as needed
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
en: { translation: en },
|
||||||
|
hi: { translation: hi },
|
||||||
|
mr: { translation: mr },
|
||||||
|
fr: { translation: fr },
|
||||||
|
// add other languages here
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(initReactI18next)
|
||||||
|
.init({
|
||||||
|
resources,
|
||||||
|
lng: 'en', // default language
|
||||||
|
fallbackLng: 'en',
|
||||||
|
//interpolation: {
|
||||||
|
// escapeValue: false, // not needed for React
|
||||||
|
//},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
||||||
|
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"failed_to_load_files": "Failed to load files. Please try again later.",
|
||||||
|
|
||||||
|
"skycrate": "Skycrate",
|
||||||
|
"hero_subtitle": "Store, Access & Share Your Files — Anytime, Anywhere!",
|
||||||
|
"hero_desc": "A simple, secure, and fast cloud storage solution for all your files. Upload, organize, and access with ease.",
|
||||||
|
"get_started": "Get Started",
|
||||||
|
"login": "Login",
|
||||||
|
"key_features": "Key Features",
|
||||||
|
"feature_easy_upload_title": "Easy Upload & Access",
|
||||||
|
"feature_easy_upload_desc": "Drag & drop, instant access.",
|
||||||
|
"feature_secure_title": "Secure & Private",
|
||||||
|
"feature_secure_desc": "End-to-end encryption.",
|
||||||
|
"feature_sharing_title": "Seamless Sharing",
|
||||||
|
"feature_sharing_desc": "Share files with one click.",
|
||||||
|
"feature_access_anywhere_title": "Access Anywhere",
|
||||||
|
"feature_access_anywhere_desc": "Works on all devices.",
|
||||||
|
"how_it_works": "How It Works",
|
||||||
|
"how_create_account_title": "Create an account",
|
||||||
|
"how_create_account_desc": "Sign up in seconds.",
|
||||||
|
"how_upload_files_title": "Upload files",
|
||||||
|
"how_upload_files_desc": "Drag & drop or select from your device.",
|
||||||
|
"how_manage_files_title": "Manage files",
|
||||||
|
"how_manage_files_desc": "Rename, move, or delete easily.",
|
||||||
|
"how_access_anytime_title": "Access anytime",
|
||||||
|
"how_access_anytime_desc": "Open files from any device.",
|
||||||
|
|
||||||
|
"not_found_title": "Page Not Found",
|
||||||
|
"not_found_description": "Sorry, we couldn't find the page you were looking for. It may have been moved or deleted.",
|
||||||
|
"go_home": "Go Home",
|
||||||
|
|
||||||
|
"login_title": "Log in",
|
||||||
|
"email_placeholder": "Enter your email",
|
||||||
|
"password_placeholder": "Enter your password",
|
||||||
|
"forgot_password": "Forgot password?",
|
||||||
|
"logging_in": "Logging In...",
|
||||||
|
"login": "Login",
|
||||||
|
"dont_have_account": "Don’t have an account?",
|
||||||
|
"sign_up": "Sign up",
|
||||||
|
"login_successful": "Login successful!",
|
||||||
|
"login_failed": "Login failed.",
|
||||||
|
"an_error_occurred": "An error occurred. Please try again.",
|
||||||
|
"logging_in_toast": "Logging in...",
|
||||||
|
|
||||||
|
"signup_title": "Sign Up",
|
||||||
|
"first_name": "First Name",
|
||||||
|
"last_name": "Last Name",
|
||||||
|
"email_placeholder": "Enter your email",
|
||||||
|
"password_placeholder": "Enter your password",
|
||||||
|
"confirm_password_placeholder": "Confirm your password",
|
||||||
|
"signing_up": "Signing Up...",
|
||||||
|
"sign_up": "Sign Up",
|
||||||
|
"already_have_account": "Already have an account?",
|
||||||
|
"login": "Login",
|
||||||
|
"passwords_do_not_match": "Passwords do not match.",
|
||||||
|
"registering": "Registering...",
|
||||||
|
"signup_failed": "Signup failed.",
|
||||||
|
"folder_creation_failed": "Failed to create user folder.",
|
||||||
|
"signup_success": "Successfully registered and folder created!",
|
||||||
|
"an_error_occurred": "An error occurred. Please try again.",
|
||||||
|
|
||||||
|
"footer_brand": "Skycrate",
|
||||||
|
"footer_tagline": "Your secure cloud storage solution for all your digital needs.",
|
||||||
|
"footer_quick_links": "Quick Links",
|
||||||
|
"footer_about_us": "About Us",
|
||||||
|
"footer_features": "Features",
|
||||||
|
"footer_how_it_works": "How It Works",
|
||||||
|
"footer_contact": "Contact",
|
||||||
|
"footer_email": "support@drivethru.com",
|
||||||
|
"footer_phone": "+91 3628206234",
|
||||||
|
"footer_address": "123 Cloud Street, Digital City",
|
||||||
|
"footer_newsletter_title": "Stay Updated",
|
||||||
|
"footer_newsletter_desc": "Get exclusive tips, updates on new features, and special offers directly in your inbox.",
|
||||||
|
"footer_newsletter_placeholder": "Enter your email",
|
||||||
|
"footer_newsletter_button": "Subscribe to Newsletter",
|
||||||
|
"subscribe_success": "You have successfully subscribed!",
|
||||||
|
"footer_rights": "All rights reserved.",
|
||||||
|
"footer_privacy_policy": "Privacy Policy",
|
||||||
|
"footer_terms_of_service": "Terms of Service",
|
||||||
|
"footer_cookie_policy": "Cookie Policy",
|
||||||
|
|
||||||
|
"sidebar_logging_out": "Logging out...",
|
||||||
|
"sidebar_logged_out": "Logged out successfully!",
|
||||||
|
"sidebar_open_sidebar": "Open sidebar",
|
||||||
|
"sidebar_brand": "Skycrate",
|
||||||
|
"sidebar_open_user_menu": "Open user menu",
|
||||||
|
"sidebar_user_photo": "User Photo",
|
||||||
|
"sidebar_logout": "Log out",
|
||||||
|
"sidebar_starred": "Starred"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"dashboard": "Tableau de bord",
|
||||||
|
"failed_to_load_files": "Échec du chargement des fichiers. Veuillez réessayer plus tard.",
|
||||||
|
|
||||||
|
"skycrate": "Skycrate",
|
||||||
|
"hero_subtitle": "Stockez, accédez et partagez vos fichiers — à tout moment, partout !",
|
||||||
|
"hero_desc": "Une solution de stockage cloud simple, sécurisée et rapide pour tous vos fichiers. Téléchargez, organisez et accédez facilement.",
|
||||||
|
"get_started": "Commencer",
|
||||||
|
"login": "Connexion",
|
||||||
|
"key_features": "Fonctionnalités clés",
|
||||||
|
"feature_easy_upload_title": "Téléversement et accès faciles",
|
||||||
|
"feature_easy_upload_desc": "Glissez-déposez, accès instantané.",
|
||||||
|
"feature_secure_title": "Sécurisé et privé",
|
||||||
|
"feature_secure_desc": "Chiffrement de bout en bout.",
|
||||||
|
"feature_sharing_title": "Partage sans effort",
|
||||||
|
"feature_sharing_desc": "Partagez des fichiers en un clic.",
|
||||||
|
"feature_access_anywhere_title": "Accès partout",
|
||||||
|
"feature_access_anywhere_desc": "Fonctionne sur tous les appareils.",
|
||||||
|
"how_it_works": "Comment ça marche",
|
||||||
|
"how_create_account_title": "Créer un compte",
|
||||||
|
"how_create_account_desc": "Inscrivez-vous en quelques secondes.",
|
||||||
|
"how_upload_files_title": "Téléverser des fichiers",
|
||||||
|
"how_upload_files_desc": "Glissez-déposez ou sélectionnez depuis votre appareil.",
|
||||||
|
"how_manage_files_title": "Gérer les fichiers",
|
||||||
|
"how_manage_files_desc": "Renommez, déplacez ou supprimez facilement.",
|
||||||
|
"how_access_anytime_title": "Accès à tout moment",
|
||||||
|
"how_access_anytime_desc": "Ouvrez des fichiers depuis n'importe quel appareil.",
|
||||||
|
|
||||||
|
"not_found_title": "Page non trouvée",
|
||||||
|
"not_found_description": "Désolé, nous n'avons pas pu trouver la page que vous cherchiez. Elle a peut-être été déplacée ou supprimée.",
|
||||||
|
"go_home": "Accueil",
|
||||||
|
|
||||||
|
"login_title": "Connexion",
|
||||||
|
"email_placeholder": "Entrez votre e-mail",
|
||||||
|
"password_placeholder": "Entrez votre mot de passe",
|
||||||
|
"forgot_password": "Mot de passe oublié ?",
|
||||||
|
"logging_in": "Connexion...",
|
||||||
|
"login": "Connexion",
|
||||||
|
"dont_have_account": "Vous n'avez pas de compte ?",
|
||||||
|
"sign_up": "S'inscrire",
|
||||||
|
"login_successful": "Connexion réussie !",
|
||||||
|
"login_failed": "Échec de la connexion.",
|
||||||
|
"an_error_occurred": "Une erreur s'est produite. Veuillez réessayer.",
|
||||||
|
"logging_in_toast": "Connexion en cours...",
|
||||||
|
|
||||||
|
"sign_up": "S'inscrire",
|
||||||
|
"first_name": "Prénom",
|
||||||
|
"last_name": "Nom de famille",
|
||||||
|
"email_placeholder": "Entrez votre e-mail",
|
||||||
|
"password_placeholder": "Entrez votre mot de passe",
|
||||||
|
"confirm_password_placeholder": "Confirmez votre mot de passe",
|
||||||
|
"already_have_account": "Vous avez déjà un compte ?",
|
||||||
|
"login": "Connexion",
|
||||||
|
"signing_up": "Inscription...",
|
||||||
|
"passwords_do_not_match": "Les mots de passe ne correspondent pas.",
|
||||||
|
"registering": "Enregistrement...",
|
||||||
|
"signup_failed": "Échec de l'inscription.",
|
||||||
|
"failed_create_folder": "Échec de la création du dossier utilisateur.",
|
||||||
|
"signup_success": "Inscription réussie et dossier créé !",
|
||||||
|
"an_error_occurred": "Une erreur s'est produite. Veuillez réessayer.",
|
||||||
|
|
||||||
|
"footer_brand": "Skycrate",
|
||||||
|
"footer_tagline": "Votre solution de stockage cloud sécurisée pour tous vos besoins numériques.",
|
||||||
|
"footer_quick_links": "Liens rapides",
|
||||||
|
"footer_about_us": "À propos",
|
||||||
|
"footer_features": "Fonctionnalités",
|
||||||
|
"footer_how_it_works": "Comment ça marche",
|
||||||
|
"footer_contact": "Contact",
|
||||||
|
"footer_email": "support@drivethru.com",
|
||||||
|
"footer_phone": "+91 3628206234",
|
||||||
|
"footer_address": "123 Rue du Cloud, Ville Digitale",
|
||||||
|
"footer_newsletter_title": "Restez informé",
|
||||||
|
"footer_newsletter_desc": "Recevez des conseils exclusifs, des mises à jour sur les nouvelles fonctionnalités et des offres spéciales directement dans votre boîte de réception.",
|
||||||
|
"footer_newsletter_placeholder": "Entrez votre e-mail",
|
||||||
|
"footer_newsletter_button": "S'abonner à la newsletter",
|
||||||
|
"subscribe_success": "Vous vous êtes abonné avec succès !",
|
||||||
|
"footer_rights": "Tous droits réservés.",
|
||||||
|
"footer_privacy_policy": "Politique de confidentialité",
|
||||||
|
"footer_terms_of_service": "Conditions d'utilisation",
|
||||||
|
"footer_cookie_policy": "Politique relative aux cookies",
|
||||||
|
|
||||||
|
"sidebar_logging_out": "Déconnexion...",
|
||||||
|
"sidebar_logged_out": "Déconnecté avec succès !",
|
||||||
|
"sidebar_open_sidebar": "Ouvrir la barre latérale",
|
||||||
|
"sidebar_brand": "Skycrate",
|
||||||
|
"sidebar_open_user_menu": "Ouvrir le menu utilisateur",
|
||||||
|
"sidebar_user_photo": "Photo de l'utilisateur",
|
||||||
|
"sidebar_logout": "Se déconnecter",
|
||||||
|
"sidebar_starred": "Favoris"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"dashboard": "डैशबोर्ड",
|
||||||
|
"failed_to_load_files": "फ़ाइलें लोड करने में विफल। कृपया बाद में पुनः प्रयास करें।",
|
||||||
|
|
||||||
|
"skycrate": "Skycrate",
|
||||||
|
"hero_subtitle": "अपनी फ़ाइलें संग्रहित करें, एक्सेस करें और साझा करें — कभी भी, कहीं भी!",
|
||||||
|
"hero_desc": "आपकी सभी फ़ाइलों के लिए एक सरल, सुरक्षित और तेज़ क्लाउड स्टोरेज समाधान। अपलोड करें, व्यवस्थित करें और आसानी से एक्सेस करें।",
|
||||||
|
"get_started": "शुरू करें",
|
||||||
|
"login": "लॉगिन",
|
||||||
|
"key_features": "मुख्य विशेषताएं",
|
||||||
|
"feature_easy_upload_title": "सरल अपलोड और एक्सेस",
|
||||||
|
"feature_easy_upload_desc": "ड्रैग और ड्रॉप करें, त्वरित एक्सेस पाएं।",
|
||||||
|
"feature_secure_title": "सुरक्षित और निजी",
|
||||||
|
"feature_secure_desc": "एंड-टू-एंड एन्क्रिप्शन।",
|
||||||
|
"feature_sharing_title": "बिना रुकावट साझाकरण",
|
||||||
|
"feature_sharing_desc": "एक क्लिक में फ़ाइलें साझा करें।",
|
||||||
|
"feature_access_anywhere_title": "कहीं से भी एक्सेस करें",
|
||||||
|
"feature_access_anywhere_desc": "सभी डिवाइस पर कार्य करता है।",
|
||||||
|
|
||||||
|
"how_it_works": "यह कैसे कार्य करता है",
|
||||||
|
"how_create_account_title": "खाता बनाएं",
|
||||||
|
"how_create_account_desc": "कुछ ही सेकंड में साइन अप करें।",
|
||||||
|
"how_upload_files_title": "फ़ाइलें अपलोड करें",
|
||||||
|
"how_upload_files_desc": "ड्रैग और ड्रॉप करें या डिवाइस से चुनें।",
|
||||||
|
"how_manage_files_title": "फ़ाइलें प्रबंधित करें",
|
||||||
|
"how_manage_files_desc": "आसानी से नाम बदलें, स्थानांतरित करें या हटाएं।",
|
||||||
|
"how_access_anytime_title": "कभी भी एक्सेस करें",
|
||||||
|
"how_access_anytime_desc": "किसी भी डिवाइस से फ़ाइलें खोलें।",
|
||||||
|
|
||||||
|
"not_found_title": "पृष्ठ नहीं मिला",
|
||||||
|
"not_found_description": "क्षमा करें, हम वह पृष्ठ नहीं ढूंढ सके जिसे आप खोज रहे थे। यह हटाया गया हो सकता है या स्थानांतरित कर दिया गया हो।",
|
||||||
|
"go_home": "मुख्य पृष्ठ पर जाएं",
|
||||||
|
|
||||||
|
"login_title": "लॉग इन करें",
|
||||||
|
"email_placeholder": "अपना ईमेल दर्ज करें",
|
||||||
|
"password_placeholder": "अपना पासवर्ड दर्ज करें",
|
||||||
|
"forgot_password": "पासवर्ड भूल गए?",
|
||||||
|
"logging_in": "लॉग इन किया जा रहा है...",
|
||||||
|
"login": "लॉगिन",
|
||||||
|
"dont_have_account": "कोई खाता नहीं है?",
|
||||||
|
"sign_up": "साइन अप करें",
|
||||||
|
"login_successful": "सफलतापूर्वक लॉगिन हुआ!",
|
||||||
|
"login_failed": "लॉगिन विफल रहा।",
|
||||||
|
"an_error_occurred": "एक त्रुटि हुई। कृपया पुनः प्रयास करें।",
|
||||||
|
"logging_in_toast": "लॉग इन किया जा रहा है...",
|
||||||
|
|
||||||
|
"signup_title": "साइन अप करें",
|
||||||
|
"first_name": "पहला नाम",
|
||||||
|
"last_name": "अंतिम नाम",
|
||||||
|
"email_placeholder": "अपना ईमेल दर्ज करें",
|
||||||
|
"password_placeholder": "अपना पासवर्ड दर्ज करें",
|
||||||
|
"confirm_password_placeholder": "अपना पासवर्ड पुष्टि करें",
|
||||||
|
"signing_up": "साइन अप किया जा रहा है...",
|
||||||
|
"sign_up": "साइन अप करें",
|
||||||
|
"already_have_account": "पहले से ही खाता है?",
|
||||||
|
"login": "लॉगिन",
|
||||||
|
"passwords_do_not_match": "पासवर्ड मेल नहीं खा रहे हैं।",
|
||||||
|
"registering": "पंजीकरण किया जा रहा है...",
|
||||||
|
"signup_failed": "साइन अप विफल रहा।",
|
||||||
|
"folder_creation_failed": "यूज़र फ़ोल्डर बनाने में विफल।",
|
||||||
|
"signup_success": "सफलतापूर्वक पंजीकरण हुआ और फ़ोल्डर बनाया गया!",
|
||||||
|
"an_error_occurred": "एक त्रुटि हुई। कृपया पुनः प्रयास करें।",
|
||||||
|
|
||||||
|
"footer_brand": "Skycrate",
|
||||||
|
"footer_tagline": "आपकी सभी डिजिटल आवश्यकताओं के लिए सुरक्षित क्लाउड स्टोरेज समाधान।",
|
||||||
|
"footer_quick_links": "त्वरित लिंक",
|
||||||
|
"footer_about_us": "हमारे बारे में",
|
||||||
|
"footer_features": "विशेषताएं",
|
||||||
|
"footer_how_it_works": "यह कैसे कार्य करता है",
|
||||||
|
"footer_contact": "संपर्क करें",
|
||||||
|
"footer_email": "support@drivethru.com",
|
||||||
|
"footer_phone": "+91 3628206234",
|
||||||
|
"footer_address": "123 क्लाउड स्ट्रीट, डिजिटल सिटी",
|
||||||
|
"footer_newsletter_title": "अपडेट प्राप्त करें",
|
||||||
|
"footer_newsletter_desc": "विशेष सुझाव, नई सुविधाओं के अपडेट और ऑफ़र सीधे अपने इनबॉक्स में पाएं।",
|
||||||
|
"footer_newsletter_placeholder": "अपना ईमेल दर्ज करें",
|
||||||
|
"footer_newsletter_button": "न्यूज़लेटर की सदस्यता लें",
|
||||||
|
"subscribe_success": "आपने सफलतापूर्वक सदस्यता ली है!",
|
||||||
|
"footer_rights": "सभी अधिकार सुरक्षित।",
|
||||||
|
"footer_privacy_policy": "गोपनीयता नीति",
|
||||||
|
"footer_terms_of_service": "सेवा की शर्तें",
|
||||||
|
"footer_cookie_policy": "कुकी नीति",
|
||||||
|
|
||||||
|
"sidebar_logging_out": "लॉग आउट किया जा रहा है...",
|
||||||
|
"sidebar_logged_out": "सफलतापूर्वक लॉग आउट हुआ!",
|
||||||
|
"sidebar_open_sidebar": "साइडबार खोलें",
|
||||||
|
"sidebar_brand": "Skycrate",
|
||||||
|
"sidebar_open_user_menu": "उपयोगकर्ता मेनू खोलें",
|
||||||
|
"sidebar_user_photo": "उपयोगकर्ता फोटो",
|
||||||
|
"sidebar_logout": "लॉग आउट",
|
||||||
|
"sidebar_starred": "चिह्नित"
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"dashboard": "डॅशबोर्ड",
|
||||||
|
"failed_to_load_files": "फायली लोड करण्यात अयशस्वी. कृपया नंतर पुन्हा प्रयत्न करा.",
|
||||||
|
|
||||||
|
"skycrate": "Skycrate",
|
||||||
|
"hero_subtitle": "तुमच्या फायली साठवा, प्रवेश मिळवा आणि शेअर करा — कधीही, कुठेही!",
|
||||||
|
"hero_desc": "सर्व फायलींसाठी एक साधे, सुरक्षित आणि जलद क्लाऊड स्टोरेज सोल्यूशन. अपलोड करा, व्यवस्थापित करा आणि सहजपणे वापरा.",
|
||||||
|
"get_started": "सुरुवात करा",
|
||||||
|
"login": "लॉगिन",
|
||||||
|
"key_features": "मुख्य वैशिष्ट्ये",
|
||||||
|
"feature_easy_upload_title": "सोपे अपलोड आणि प्रवेश",
|
||||||
|
"feature_easy_upload_desc": "ड्रॅग आणि ड्रॉप, त्वरित प्रवेश.",
|
||||||
|
"feature_secure_title": "सुरक्षित आणि खाजगी",
|
||||||
|
"feature_secure_desc": "संपूर्ण एन्क्रिप्शन.",
|
||||||
|
"feature_sharing_title": "सुलभ शेअरिंग",
|
||||||
|
"feature_sharing_desc": "एक क्लिकमध्ये फायली शेअर करा.",
|
||||||
|
"feature_access_anywhere_title": "कोठूनही प्रवेश",
|
||||||
|
"feature_access_anywhere_desc": "सर्व डिव्हाइसेसवर कार्यरत.",
|
||||||
|
|
||||||
|
"how_it_works": "हे कसे कार्य करते",
|
||||||
|
"how_create_account_title": "खाते तयार करा",
|
||||||
|
"how_create_account_desc": "काही सेकंदांत साइन अप करा.",
|
||||||
|
"how_upload_files_title": "फायली अपलोड करा",
|
||||||
|
"how_upload_files_desc": "ड्रॅग आणि ड्रॉप करा किंवा तुमच्या डिव्हाइसमधून निवडा.",
|
||||||
|
"how_manage_files_title": "फायली व्यवस्थापित करा",
|
||||||
|
"how_manage_files_desc": "नाव बदला, हलवा किंवा हटवा.",
|
||||||
|
"how_access_anytime_title": "कधीही प्रवेश करा",
|
||||||
|
"how_access_anytime_desc": "कोणत्याही डिव्हाइसवरून फायली उघडा.",
|
||||||
|
|
||||||
|
"not_found_title": "पृष्ठ सापडले नाही",
|
||||||
|
"not_found_description": "क्षमस्व, तुम्ही शोधत असलेले पृष्ठ आम्हाला सापडले नाही. कदाचित ते हलवले गेले असेल किंवा हटवले गेले असेल.",
|
||||||
|
"go_home": "मुख्य पृष्ठावर जा",
|
||||||
|
|
||||||
|
"login_title": "लॉग इन करा",
|
||||||
|
"email_placeholder": "तुमचा ईमेल टाका",
|
||||||
|
"password_placeholder": "तुमचा पासवर्ड टाका",
|
||||||
|
"forgot_password": "पासवर्ड विसरलात?",
|
||||||
|
"logging_in": "लॉग इन करत आहे...",
|
||||||
|
"login": "लॉग इन",
|
||||||
|
"dont_have_account": "अजून खाते नाही?",
|
||||||
|
"sign_up": "साइन अप",
|
||||||
|
"login_successful": "यशस्वीरित्या लॉग इन झाले!",
|
||||||
|
"login_failed": "लॉग इन अयशस्वी.",
|
||||||
|
"an_error_occurred": "त्रुटी आली. कृपया पुन्हा प्रयत्न करा.",
|
||||||
|
"logging_in_toast": "लॉग इन होत आहे...",
|
||||||
|
|
||||||
|
"signup_title": "साइन अप करा",
|
||||||
|
"first_name": "पहिले नाव",
|
||||||
|
"last_name": "आडनाव",
|
||||||
|
"email_placeholder": "तुमचा ईमेल टाका",
|
||||||
|
"password_placeholder": "तुमचा पासवर्ड टाका",
|
||||||
|
"confirm_password_placeholder": "तुमचा पासवर्ड पुन्हा टाका",
|
||||||
|
"signing_up": "साइन अप करत आहे...",
|
||||||
|
"sign_up": "साइन अप",
|
||||||
|
"already_have_account": "आधीच खाते आहे?",
|
||||||
|
"login": "लॉग इन",
|
||||||
|
"passwords_do_not_match": "पासवर्ड जुळत नाहीत.",
|
||||||
|
"registering": "नोंदणी करत आहे...",
|
||||||
|
"signup_failed": "साइन अप अयशस्वी.",
|
||||||
|
"folder_creation_failed": "वापरकर्त्याची फोल्डर तयार करण्यात अयशस्वी.",
|
||||||
|
"signup_success": "यशस्वीरित्या नोंदणी झाली आणि फोल्डर तयार झाला!",
|
||||||
|
"an_error_occurred": "त्रुटी आली. कृपया पुन्हा प्रयत्न करा.",
|
||||||
|
|
||||||
|
"footer_brand": "Skycrate",
|
||||||
|
"footer_tagline": "तुमच्या सर्व डिजिटल गरजांसाठी सुरक्षित क्लाऊड स्टोरेज सोल्यूशन.",
|
||||||
|
"footer_quick_links": "त्वरित दुवे",
|
||||||
|
"footer_about_us": "आमच्याबद्दल",
|
||||||
|
"footer_features": "वैशिष्ट्ये",
|
||||||
|
"footer_how_it_works": "हे कसे कार्य करते",
|
||||||
|
"footer_contact": "संपर्क",
|
||||||
|
"footer_email": "support@drivethru.com",
|
||||||
|
"footer_phone": "+९१ ३६२८२०६२३४",
|
||||||
|
"footer_address": "१२३ क्लाऊड स्ट्रीट, डिजिटल सिटी",
|
||||||
|
"footer_newsletter_title": "अपडेट मिळवा",
|
||||||
|
"footer_newsletter_desc": "विशेष टिप्स, नवीन वैशिष्ट्यांवरील अपडेट्स आणि खास ऑफर्स तुमच्या इनबॉक्समध्ये मिळवा.",
|
||||||
|
"footer_newsletter_placeholder": "तुमचा ईमेल टाका",
|
||||||
|
"footer_newsletter_button": "न्यूजलेटरची सदस्यता घ्या",
|
||||||
|
"subscribe_success": "तुमची सदस्यता यशस्वीरित्या घेतली गेली आहे!",
|
||||||
|
"footer_rights": "सर्व हक्क राखीव.",
|
||||||
|
"footer_privacy_policy": "गोपनीयता धोरण",
|
||||||
|
"footer_terms_of_service": "सेवेच्या अटी",
|
||||||
|
"footer_cookie_policy": "कुकी धोरण",
|
||||||
|
|
||||||
|
"sidebar_logging_out": "लॉग आउट करत आहे...",
|
||||||
|
"sidebar_logged_out": "यशस्वीरित्या लॉग आउट झाले!",
|
||||||
|
"sidebar_open_sidebar": "साइडबार उघडा",
|
||||||
|
"sidebar_brand": "Skycrate",
|
||||||
|
"sidebar_open_user_menu": "वापरकर्ता मेनू उघडा",
|
||||||
|
"sidebar_user_photo": "वापरकर्त्याचा फोटो",
|
||||||
|
"sidebar_logout": "लॉग आउट",
|
||||||
|
"sidebar_starred": "आवडते"
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import './i18n'; // for multilingual functionality
|
||||||
|
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { useState, useEffect } from "react";
|
|||||||
import { FiEye, FiEyeOff } from "react-icons/fi";
|
import { FiEye, FiEyeOff } from "react-icons/fi";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import toast from "react-hot-toast"; // Import React Hot Toast
|
import toast from "react-hot-toast"; // Import React Hot Toast
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const API_URL = import.meta.env.VITE_API_URL; // Using .env variable
|
const API_URL = import.meta.env.VITE_API_URL; // Using .env variable
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
@@ -28,7 +30,7 @@ const Login = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// Show loading toast
|
// Show loading toast
|
||||||
const toastId = toast.loading("Logging in...");
|
const toastId = toast.loading(t("logging_in_toast"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/api/login`, {
|
const response = await fetch(`${API_URL}/api/login`, {
|
||||||
@@ -61,18 +63,17 @@ const Login = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Show success toast
|
// Show success toast
|
||||||
toast.success("Login successful!");
|
toast.success(t("login_successful"));
|
||||||
|
|
||||||
// Redirect to Dashboard
|
// Redirect to Dashboard
|
||||||
navigate("/dashboard");
|
navigate("/dashboard");
|
||||||
} else {
|
} else {
|
||||||
// Show error toast if login fails
|
// Show error toast if login fails
|
||||||
toast.error(data.message || "Login failed.");
|
toast.error(data.message || t("login_failed"));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Dismiss the loading toast and show error
|
// Dismiss the loading toast and show error
|
||||||
toast.dismiss(toastId);
|
toast.dismiss(toastId);
|
||||||
toast.error("An error occurred. Please try again.", error);
|
toast.error(t("an_error_occurred"));
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -82,7 +83,7 @@ const Login = () => {
|
|||||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
|
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
|
||||||
<div className="w-full max-w-md bg-white rounded-4xl shadow-lg p-8">
|
<div className="w-full max-w-md bg-white rounded-4xl shadow-lg p-8">
|
||||||
<h1 className="text-2xl font-bold mb-6 text-gray-900 text-center">
|
<h1 className="text-2xl font-bold mb-6 text-gray-900 text-center">
|
||||||
Log in
|
{t("login_title")}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
@@ -91,7 +92,7 @@ const Login = () => {
|
|||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
id="email"
|
id="email"
|
||||||
placeholder="Enter your email"
|
placeholder={t("email_placeholder")}
|
||||||
className="w-full border border-gray-300 rounded-l-lg px-4 py-4 focus:outline-none focus:border-blue-500"
|
className="w-full border border-gray-300 rounded-l-lg px-4 py-4 focus:outline-none focus:border-blue-500"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
@@ -104,7 +105,7 @@ const Login = () => {
|
|||||||
<input
|
<input
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
id="password"
|
id="password"
|
||||||
placeholder="Enter your password"
|
placeholder={t("password_placeholder")}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:border-blue-500 pr-10"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:border-blue-500 pr-10"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
@@ -124,7 +125,7 @@ const Login = () => {
|
|||||||
to="#!"
|
to="#!"
|
||||||
className="text-sm text-blue-600 hover:underline inline-block"
|
className="text-sm text-blue-600 hover:underline inline-block"
|
||||||
>
|
>
|
||||||
Forgot password?
|
{t("forgot_password")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@@ -132,17 +133,17 @@ const Login = () => {
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full py-3 bg-gradient-to-r from-[#1877F2] to-[#0E458C] hover:from-[#0E458C] hover:to-[#1877F2] text-white font-semibold rounded-full shadow-md transition duration-300"
|
className="w-full py-3 bg-gradient-to-r from-[#1877F2] to-[#0E458C] hover:from-[#0E458C] hover:to-[#1877F2] text-white font-semibold rounded-full shadow-md transition duration-300"
|
||||||
>
|
>
|
||||||
{loading ? "Logging In..." : "Login"}
|
{loading ? t("logging_in") : t("login")}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div className="text-center mt-6">
|
<div className="text-center mt-6">
|
||||||
<p className="text-gray-700">
|
<p className="text-gray-700">
|
||||||
Don’t have an account?{" "}
|
{t("dont_have_account")}{" "}
|
||||||
<Link
|
<Link
|
||||||
to="/signup"
|
to="/signup"
|
||||||
className="text-emerald-500 hover:underline font-medium"
|
className="text-emerald-500 hover:underline font-medium"
|
||||||
>
|
>
|
||||||
Sign up
|
{t("sign_up")}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { useState } from "react";
|
|||||||
import { FiEye, FiEyeOff } from "react-icons/fi";
|
import { FiEye, FiEyeOff } from "react-icons/fi";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import toast, { Toaster } from "react-hot-toast";
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const API_URL = import.meta.env.VITE_API_URL;
|
const API_URL = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
const SignUp = () => {
|
const SignUp = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -30,12 +32,12 @@ const SignUp = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (formData.password !== formData.confirmPassword) {
|
if (formData.password !== formData.confirmPassword) {
|
||||||
toast.error("Passwords do not match.");
|
toast.error(t("passwords_do_not_match"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const toastId = toast.loading("Registering...");
|
const toastId = toast.loading(t("registering"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1️⃣ Sign up the user
|
// 1️⃣ Sign up the user
|
||||||
@@ -52,7 +54,7 @@ const SignUp = () => {
|
|||||||
const signupData = await signupRes.json();
|
const signupData = await signupRes.json();
|
||||||
|
|
||||||
if (!signupRes.ok) {
|
if (!signupRes.ok) {
|
||||||
toast.error(signupData.message || "Signup failed.", { id: toastId });
|
toast.error(signupData.message || t("signup_failed"), { id: toastId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +68,9 @@ const SignUp = () => {
|
|||||||
|
|
||||||
if (!folderRes.ok) {
|
if (!folderRes.ok) {
|
||||||
// you might choose to roll back user creation or just notify
|
// you might choose to roll back user creation or just notify
|
||||||
toast.error("Failed to create user folder.", { id: toastId });
|
toast.error(t("failed_create_folder"), { id: toastId });
|
||||||
} else {
|
} else {
|
||||||
toast.success("Successfully registered and folder created!", {
|
toast.success(t("signup_success"), { id: toastId });
|
||||||
id: toastId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3️⃣ Redirect to login after a short delay
|
// 3️⃣ Redirect to login after a short delay
|
||||||
@@ -79,7 +79,7 @@ const SignUp = () => {
|
|||||||
}, 1500);
|
}, 1500);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
toast.error("An error occurred. Please try again.", { id: toastId });
|
toast.error(t("an_error_occurred"), { id: toastId });
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -89,12 +89,12 @@ const SignUp = () => {
|
|||||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-6">
|
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-6">
|
||||||
<Toaster position="top-right" />
|
<Toaster position="top-right" />
|
||||||
<div className="w-full max-w-md bg-white rounded-2xl shadow-lg p-8">
|
<div className="w-full max-w-md bg-white rounded-2xl shadow-lg p-8">
|
||||||
<h1 className="text-2xl font-bold text-gray-900 mb-6">Sign Up</h1>
|
<h1 className="text-2xl font-bold text-gray-900 mb-6">{t("sign_up")}</h1>
|
||||||
<form className="space-y-4" onSubmit={handleSubmit}>
|
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="firstname"
|
name="firstname"
|
||||||
placeholder="First Name"
|
placeholder={t("first_name")}
|
||||||
value={formData.firstname}
|
value={formData.firstname}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
@@ -103,7 +103,7 @@ const SignUp = () => {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="lastname"
|
name="lastname"
|
||||||
placeholder="Last Name"
|
placeholder={t("last_name")}
|
||||||
value={formData.lastname}
|
value={formData.lastname}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
@@ -112,7 +112,7 @@ const SignUp = () => {
|
|||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
placeholder="Enter your email"
|
placeholder={t("email_placeholder")}
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
@@ -124,7 +124,7 @@ const SignUp = () => {
|
|||||||
<input
|
<input
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
name="password"
|
name="password"
|
||||||
placeholder="Enter your password"
|
placeholder={t("password_placeholder")}
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
||||||
@@ -144,7 +144,7 @@ const SignUp = () => {
|
|||||||
<input
|
<input
|
||||||
type={showConfirmPassword ? "text" : "password"}
|
type={showConfirmPassword ? "text" : "password"}
|
||||||
name="confirmPassword"
|
name="confirmPassword"
|
||||||
placeholder="Confirm your password"
|
placeholder={t("confirm_password_placeholder")}
|
||||||
value={formData.confirmPassword}
|
value={formData.confirmPassword}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
||||||
@@ -169,18 +169,18 @@ const SignUp = () => {
|
|||||||
: "bg-gradient-to-r from-[#10B981] to-[#07533A] hover:from-[#0E458C] hover:to-[#1877F2]"
|
: "bg-gradient-to-r from-[#10B981] to-[#07533A] hover:from-[#0E458C] hover:to-[#1877F2]"
|
||||||
} text-white font-semibold rounded-lg shadow-md transition duration-300`}
|
} text-white font-semibold rounded-lg shadow-md transition duration-300`}
|
||||||
>
|
>
|
||||||
{loading ? "Signing Up..." : "Sign Up"}
|
{loading ? t("signing_up") : t("sign_up")}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Redirect to Login */}
|
{/* Redirect to Login */}
|
||||||
<p className="text-center mt-4 text-gray-700">
|
<p className="text-center mt-4 text-gray-700">
|
||||||
Already have an account?{" "}
|
{t("already_have_account")}{" "}
|
||||||
<Link
|
<Link
|
||||||
to="/login"
|
to="/login"
|
||||||
className="text-blue-500 hover:underline font-medium"
|
className="text-blue-500 hover:underline font-medium"
|
||||||
>
|
>
|
||||||
Login
|
{t("login")}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
import Sidebar from "../../components/Sidebar";
|
import Sidebar from "../../components/Sidebar";
|
||||||
import FileList from "../../components/FileList";
|
import FileList from "../../components/FileList";
|
||||||
import FileUploadModal from "../../components/FileUploadModal";
|
import FileUploadModal from "../../components/FileUploadModal";
|
||||||
import { FiPlus } from "react-icons/fi";
|
import { FiPlus } from "react-icons/fi";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
|
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const API_URL = import.meta.env.VITE_API_URL;
|
const API_URL = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
const isUserLoggedIn = () => {
|
const isUserLoggedIn = () => {
|
||||||
const token = localStorage.getItem("token");
|
const token = localStorage.getItem("token");
|
||||||
const username = localStorage.getItem("username");
|
const username = localStorage.getItem("username");
|
||||||
@@ -36,7 +39,7 @@ const Dashboard = () => {
|
|||||||
setFiles(data);
|
setFiles(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch files:", error);
|
console.error("Failed to fetch files:", error);
|
||||||
setError("Failed to load files. Please try again later.");
|
setError(t("failed_to_load_files"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,6 +49,7 @@ const Dashboard = () => {
|
|||||||
} else {
|
} else {
|
||||||
fetchFiles();
|
fetchFiles();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -54,7 +58,7 @@ const Dashboard = () => {
|
|||||||
<div className="p-4 sm:ml-64">
|
<div className="p-4 sm:ml-64">
|
||||||
<div className="p-4 border-2 border-gray-200 border-dashed rounded-lg mt-14">
|
<div className="p-4 border-2 border-gray-200 border-dashed rounded-lg mt-14">
|
||||||
<div className="w-full flex justify-between items-center">
|
<div className="w-full flex justify-between items-center">
|
||||||
<h1 className="text-2xl font-bold mb-4">Dashboard</h1>
|
<h1 className="text-2xl font-bold mb-4">{t("dashboard")}</h1>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsUploadModalOpen(true)}
|
onClick={() => setIsUploadModalOpen(true)}
|
||||||
className="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-2 text-center"
|
className="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-2 text-center"
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import Footer from "../../components/Footer";
|
import Footer from "../../components/Footer";
|
||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const DrivethruLandingPage = () => {
|
const DrivethruLandingPage = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
{
|
{
|
||||||
title: "Easy Upload & Access",
|
title: t("feature_easy_upload_title"),
|
||||||
description: "Drag & drop, instant access.",
|
description: t("feature_easy_upload_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -25,8 +27,8 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Secure & Private",
|
title: t("feature_secure_title"),
|
||||||
description: "End-to-end encryption.",
|
description: t("feature_secure_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -44,8 +46,8 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Seamless Sharing",
|
title: t("feature_sharing_title"),
|
||||||
description: "Share files with one click.",
|
description: t("feature_sharing_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -63,8 +65,8 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Access Anywhere",
|
title: t("feature_access_anywhere_title"),
|
||||||
description: "Works on all devices.",
|
description: t("feature_access_anywhere_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -85,8 +87,8 @@ const DrivethruLandingPage = () => {
|
|||||||
|
|
||||||
const howItWorks = [
|
const howItWorks = [
|
||||||
{
|
{
|
||||||
title: "Create an account",
|
title: t("how_create_account_title"),
|
||||||
description: "Sign up in seconds.",
|
description: t("how_create_account_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -104,8 +106,8 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Upload files",
|
title: t("how_upload_files_title"),
|
||||||
description: "Drag & drop or select from your device.",
|
description: t("how_upload_files_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -123,10 +125,10 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Manage files",
|
title: t("how_manage_files_title"),
|
||||||
description: "Rename, move, or delete easily.",
|
description: t("how_manage_files_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -148,8 +150,8 @@ const DrivethruLandingPage = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Access anytime",
|
title: t("how_access_anytime_title"),
|
||||||
description: "Open files from any device.",
|
description: t("how_access_anytime_desc"),
|
||||||
icon: (
|
icon: (
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6"
|
className="w-6 h-6"
|
||||||
@@ -168,6 +170,7 @@ const DrivethruLandingPage = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// UseEffect and handle....click function to handle set and handle the animation of features..
|
// UseEffect and handle....click function to handle set and handle the animation of features..
|
||||||
const [activeIndex, setActiveIndex] = useState(0);
|
const [activeIndex, setActiveIndex] = useState(0);
|
||||||
const [isPaused, setIsPaused] = useState(false);
|
const [isPaused, setIsPaused] = useState(false);
|
||||||
@@ -234,17 +237,16 @@ const DrivethruLandingPage = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl md:text-5xl font-bold text-black">
|
<h1 className="text-4xl md:text-5xl font-bold text-black">
|
||||||
Skycrate
|
{t("skycrate")}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 className="text-xl md:text-2xl font-bold mb-4 md:mb-6 text-black">
|
<h2 className="text-xl md:text-2xl font-bold mb-4 md:mb-6 text-black">
|
||||||
Store, Access & Share Your Files — Anytime, Anywhere!
|
{t("hero_subtitle")}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="text-gray-800 mb-6 md:mb-10 text-base md:text-lg">
|
<p className="text-gray-800 mb-6 md:mb-10 text-base md:text-lg">
|
||||||
A simple, secure, and fast cloud storage solution for all your
|
{t("hero_desc")}
|
||||||
files. Upload, organize, and access with ease.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Buttons */}
|
{/* Buttons */}
|
||||||
@@ -253,13 +255,13 @@ const DrivethruLandingPage = () => {
|
|||||||
to="/signup"
|
to="/signup"
|
||||||
className="bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
className="bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
||||||
>
|
>
|
||||||
Get Started
|
{t("get_started")}
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to="/login"
|
to="/login"
|
||||||
className="bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
className="bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
||||||
>
|
>
|
||||||
Login
|
{t("login")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -283,7 +285,7 @@ const DrivethruLandingPage = () => {
|
|||||||
id="features"
|
id="features"
|
||||||
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-center mb-8">Key Features</h2>
|
<h2 className="text-3xl font-bold text-center mb-8">{t("key_features")}</h2>
|
||||||
<div className="flex flex-col-reverse md:flex-row items-center gap-8 lg:gap-12">
|
<div className="flex flex-col-reverse md:flex-row items-center gap-8 lg:gap-12">
|
||||||
{/* Left Side - Image */}
|
{/* Left Side - Image */}
|
||||||
<div className="w-full md:w-1/2 flex justify-center">
|
<div className="w-full md:w-1/2 flex justify-center">
|
||||||
@@ -328,7 +330,7 @@ const DrivethruLandingPage = () => {
|
|||||||
id="howItWorks"
|
id="howItWorks"
|
||||||
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-center mb-8">How It Works</h2>
|
<h2 className="text-3xl font-bold text-center mb-8">{t("how_it_works")}</h2>
|
||||||
<div className="flex flex-col md:flex-row items-center gap-8 lg:gap-12">
|
<div className="flex flex-col md:flex-row items-center gap-8 lg:gap-12">
|
||||||
{/* Left Side - Feature List */}
|
{/* Left Side - Feature List */}
|
||||||
<div className="w-full md:w-1/2">
|
<div className="w-full md:w-1/2">
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next"; // for multilinguality
|
||||||
|
|
||||||
const NotFoundPage = () => {
|
const NotFoundPage = () => {
|
||||||
|
const { t } = useTranslation(); // for multilinguality
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center h-screen bg-gray-100 p-4">
|
<div className="flex flex-col items-center justify-center h-screen bg-gray-100 p-4">
|
||||||
{/* Placeholder SVG - Replace this with your SVG */}
|
|
||||||
<img
|
<img
|
||||||
src="/404.png"
|
src="/404.png"
|
||||||
style={{ width: "30%", height: "auto" }}
|
style={{ width: "30%", height: "auto" }}
|
||||||
alt="404 Not Found"
|
alt="404 Not Found"
|
||||||
></img>
|
/>
|
||||||
{/* Page number and title */}
|
<h2 className="text-2xl font-bold mb-4 mt-4">{t("not_found_title")}</h2>
|
||||||
<h2 className="text-2xl font-bold mb-4 mt-4">Page Not Found</h2>
|
|
||||||
|
|
||||||
{/* Description text */}
|
|
||||||
<p className="text-center text-gray-700 mb-6">
|
<p className="text-center text-gray-700 mb-6">
|
||||||
Sorry, we couldn't find the page you were looking for. It may have
|
{t("not_found_description")}
|
||||||
been moved or deleted.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Call-to-action button */}
|
|
||||||
<Link
|
<Link
|
||||||
to="/"
|
to="/"
|
||||||
className="px-6 py-2 bg-[#1877F2] text-white rounded hover:bg-blue-600 transition duration-200"
|
className="px-6 py-2 bg-[#1877F2] text-white rounded hover:bg-blue-600 transition duration-200"
|
||||||
>
|
>
|
||||||
Go Home
|
{t("go_home")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,26 +1,54 @@
|
|||||||
# CC-MINI (2025)
|
# Skycrate
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This project is now multilingual. To contribute new languages, please read the [translation guide](./TRANSLATION.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Git config
|
## Versions
|
||||||
|
- Hadoop: 3.4.1
|
||||||
|
- Java: 17
|
||||||
|
- Node: 22.14.0
|
||||||
|
- NPM: 10.9.2
|
||||||
|
|
||||||
Create a new directory for this project, and run these following commands for initalizing git:
|
## How to run?
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> You must have [Docker](https://www.docker.com/products/docker-desktop/) and [Git](https://git-scm.com/) installed on your system.
|
||||||
|
|
||||||
|
1. Clone this repository:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/kshitij-ka/cc-mini.git
|
git clone https://git.kska.io/notkshitij/Skycrate.git
|
||||||
cd cc-mini
|
|
||||||
git config --local user.name "Your name"
|
|
||||||
git config --local user.email "your@ema.il"
|
|
||||||
git config --local core.autocrlf input # For Linux/MacOS users
|
|
||||||
git config --local core.autocrlf true # For Windows users
|
|
||||||
git checkout frontend # If you're working on frontend
|
|
||||||
git checkout backend # If you're working on backend
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Where to push?
|
2. Change into the directory:
|
||||||
|
|
||||||
- For frontend, please push to [Frontend](https://github.com/kshitij-ka/cc-mini/tree/frontend/Frontend) folder in the [frontend branch](https://github.com/kshitij-ka/cc-mini/tree/frontend).
|
```shell
|
||||||
- For backend, please push to [Backend](https://github.com/kshitij-ka/cc-mini/tree/backend/Backend) folder in the [backend branch](https://github.com/kshitij-ka/cc-mini/tree/backend/).
|
cd ./Skycrate
|
||||||
- I will be merging changes from both the branches in the main branch for deploying.
|
```
|
||||||
|
|
||||||
|
3. Create a `.env` file inside the directory containing the following variables:
|
||||||
|
|
||||||
|
```env
|
||||||
|
MYSQL_PASSWORD=<set-a-strong-password>
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Please choose a strong password, since it will be used for your MySQL database.
|
||||||
|
|
||||||
|
4. Execute the Docker Compose file:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker-compose -f docker-compose.yaml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Use `-d` flag to run in detached mode.
|
||||||
|
|
||||||
|
5. Visit `localhost:8080` to enjoy using Skycrate!
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> To stop and remove all the containers, run `docker compose down`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# TRANSLATION
|
||||||
|
|
||||||
|
This is a comprehensive guide for translation for those who wish to contribute in any language.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Add Your Language JSON File
|
||||||
|
|
||||||
|
- Go to the `Frontend/src/locales/` directory.
|
||||||
|
- Copy an existing language file (e.g., `en.json`) and rename it to your language code (e.g., `es.json` for Spanish, `de.json` for German).
|
||||||
|
- Translate all the key-value pairs in your new file.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp Frontend/src/locales/en.json Frontend/src/locales/es.json
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"skycrate": "Skycrate",
|
||||||
|
"hero_subtitle": "Store, Access & Share Your Files — Anytime, Anywhere!",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Register the Language in `Frontend/src/i18n.js`
|
||||||
|
|
||||||
|
- Open `Frontend/src/i18n.js`.
|
||||||
|
- Import your new JSON file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import en from './locales/en.json';
|
||||||
|
import fr from './locales/fr.json';
|
||||||
|
// import more languages as needed
|
||||||
|
import es from './locales/es.json'; // <-- Add this line
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
en: { translation: en },
|
||||||
|
fr: { translation: fr },
|
||||||
|
// add other languages here
|
||||||
|
es: { translation: es }, // <-- Add this line
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Update the Language Switcher
|
||||||
|
|
||||||
|
- Open `Frontend/src/components/LanguageSwitcher.jsx`.
|
||||||
|
- Add your language to the `languages` array:
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
const languages = [
|
||||||
|
{ code: 'en', label: 'English' },
|
||||||
|
{ code: 'fr', label: 'Français' },
|
||||||
|
// Add more languages as needed
|
||||||
|
{ code: 'es', label: 'Spanish' }, // <-- Add this line
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Test Your Translation
|
||||||
|
|
||||||
|
- Start the app.
|
||||||
|
- Use the language switcher to select your new language.
|
||||||
|
- Check all pages for missing or untranslated keys.
|
||||||
|
- If you see a key instead of a translation, add it to your JSON file.
|
||||||
|
|
||||||
|
## 5. Submit Your Contribution
|
||||||
|
|
||||||
|
- Double-check your translations for accuracy and completeness.
|
||||||
|
- Commit your changes to:
|
||||||
|
- `Frontend/src/locales/<your_language>.json`
|
||||||
|
- `Frontend/src/i18n.js`
|
||||||
|
- `Frontend/src/components/LanguageSwitcher.jsx`
|
||||||
|
- Open a pull request with a description of your contribution.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Thank you for making Skycrate accessible to more people!
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
services:
|
||||||
|
namenode:
|
||||||
|
image: kshitijka/hadoop-namenode:3.4.1
|
||||||
|
container_name: skycrate-hadoop-namenode
|
||||||
|
restart: on-failure:5
|
||||||
|
ports:
|
||||||
|
- "9870:9870" # Web UI
|
||||||
|
#- "9000:9000" # Hadoop; No need to expose since backend will access internally
|
||||||
|
user: "hdoop:hdoop"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
volumes:
|
||||||
|
- skycrate-hadoop_namenode:/hadoop/dfs/name
|
||||||
|
environment:
|
||||||
|
- CLUSTER_NAME=skycreate
|
||||||
|
env_file:
|
||||||
|
- ./hadoop.env
|
||||||
|
|
||||||
|
datanode:
|
||||||
|
image: kshitijka/hadoop-datanode:3.4.1
|
||||||
|
container_name: skycrate-hadoop-datanode-1
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "hdoop:hdoop"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
volumes:
|
||||||
|
- skycrate-hadoop_datanode:/hadoop/dfs/data
|
||||||
|
environment:
|
||||||
|
SERVICE_PRECONDITION: "namenode:9870"
|
||||||
|
env_file:
|
||||||
|
- ./hadoop.env
|
||||||
|
# healthcheck:
|
||||||
|
# disable: true
|
||||||
|
|
||||||
|
resourcemanager:
|
||||||
|
image: kshitijka/hadoop-resourcemanager:3.4.1
|
||||||
|
container_name: skycrate-hadoop-resourcemanager
|
||||||
|
restart: on-failure:10
|
||||||
|
user: "hdoop:hdoop"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
environment:
|
||||||
|
SERVICE_PRECONDITION: "namenode:9000 namenode:9870 datanode:9864"
|
||||||
|
env_file:
|
||||||
|
- ./hadoop.env
|
||||||
|
# healthcheck:
|
||||||
|
# disable: true
|
||||||
|
|
||||||
|
nodemanager:
|
||||||
|
image: kshitijka/hadoop-nodemanager:3.4.1
|
||||||
|
container_name: skycrate-hadoop-nodemanager
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "hdoop:hdoop"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
environment:
|
||||||
|
SERVICE_PRECONDITION: "namenode:9000 namenode:9870 datanode:9864 resourcemanager:8088"
|
||||||
|
env_file:
|
||||||
|
- ./hadoop.env
|
||||||
|
# healthcheck:
|
||||||
|
# disable: true
|
||||||
|
|
||||||
|
historyserver:
|
||||||
|
image: kshitijka/hadoop-historyserver:3.4.1
|
||||||
|
container_name: skycrate-hadoop-historyserver
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "hdoop:hdoop"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
environment:
|
||||||
|
SERVICE_PRECONDITION: "namenode:9000 namenode:9870 datanode:9864 resourcemanager:8088"
|
||||||
|
volumes:
|
||||||
|
- skycrate-hadoop_historyserver:/hadoop/yarn/timeline
|
||||||
|
env_file:
|
||||||
|
- ./hadoop.env
|
||||||
|
# healthcheck:
|
||||||
|
# disable: true
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8
|
||||||
|
container_name: skycrate-db
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "1000:1000"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
environment:
|
||||||
|
- MYSQL_DATABASE=${DB_NAME}
|
||||||
|
- MYSQL_USER=${DB_USERNAME}
|
||||||
|
- MYSQL_PASSWORD=${DB_PASSWORD}
|
||||||
|
- MYSQL_RANDOM_ROOT_PASSWORD=yes
|
||||||
|
volumes:
|
||||||
|
- skycrate-db:/var/lib/mysql
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: kshitijka/skycrate-frontend:1.0
|
||||||
|
container_name: skycrate-frontend
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "skycrateFront:skycrateFront"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: kshitijka/skycrate-backend:1.5
|
||||||
|
container_name: skycrate-backend
|
||||||
|
restart: on-failure:5
|
||||||
|
user: "skycrateBack:skycrateBack"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges=true
|
||||||
|
networks:
|
||||||
|
- skycrate-internal
|
||||||
|
ports:
|
||||||
|
- "8080:8080" # If you change, update in Frontend/.env file too and rebuild the image
|
||||||
|
environment:
|
||||||
|
- JWT_SECRET=${JWT_SECRET} # Eg. dO9Yl9NYJOODug8y9ciMVnVMoH44Q6mXilIlZ2LXXYY=
|
||||||
|
- DB_NAME=${DB_NAME}
|
||||||
|
- DB_URI=db:3306
|
||||||
|
- DB_USERNAME=${DB_USERNAME}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD}
|
||||||
|
- HDFS_URI=hdfs://namenode:9000
|
||||||
|
- HDFS_USER=hadoopuser
|
||||||
|
- SSL_PASSWORD=tempP@ass69 # Do not change for now. Future updates will allow you to change it.
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
skycrate-hadoop_namenode:
|
||||||
|
skycrate-hadoop_datanode:
|
||||||
|
skycrate-hadoop_historyserver:
|
||||||
|
skycrate-db:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
skycrate-internal:
|
||||||
|
external: false
|
||||||
|
driver: bridge
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
CORE_CONF_fs_defaultFS=hdfs://namenode:9000
|
||||||
|
CORE_CONF_hadoop_http_staticuser_user=root
|
||||||
|
CORE_CONF_hadoop_proxyuser_hue_hosts=*
|
||||||
|
CORE_CONF_hadoop_proxyuser_hue_groups=*
|
||||||
|
CORE_CONF_io_compression_codecs=org.apache.hadoop.io.compress.SnappyCodec
|
||||||
|
|
||||||
|
HDFS_CONF_dfs_webhdfs_enabled=true
|
||||||
|
HDFS_CONF_dfs_permissions_enabled=false
|
||||||
|
HDFS_CONF_dfs_namenode_datanode_registration_ip___hostname___check=false
|
||||||
|
|
||||||
|
YARN_CONF_yarn_log___aggregation___enable=true
|
||||||
|
YARN_CONF_yarn_log_server_url=http://historyserver:8188/applicationhistory/logs/
|
||||||
|
YARN_CONF_yarn_resourcemanager_recovery_enabled=true
|
||||||
|
YARN_CONF_yarn_resourcemanager_store_class=org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore
|
||||||
|
YARN_CONF_yarn_resourcemanager_scheduler_class=org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
|
||||||
|
YARN_CONF_yarn_scheduler_capacity_root_default_maximum___allocation___mb=8192
|
||||||
|
YARN_CONF_yarn_scheduler_capacity_root_default_maximum___allocation___vcores=4
|
||||||
|
YARN_CONF_yarn_resourcemanager_fs_state___store_uri=/rmstate
|
||||||
|
YARN_CONF_yarn_resourcemanager_system___metrics___publisher_enabled=true
|
||||||
|
YARN_CONF_yarn_resourcemanager_hostname=resourcemanager
|
||||||
|
YARN_CONF_yarn_resourcemanager_address=resourcemanager:8032
|
||||||
|
YARN_CONF_yarn_resourcemanager_scheduler_address=resourcemanager:8030
|
||||||
|
YARN_CONF_yarn_resourcemanager_resource__tracker_address=resourcemanager:8031
|
||||||
|
YARN_CONF_yarn_timeline___service_enabled=true
|
||||||
|
YARN_CONF_yarn_timeline___service_generic___application___history_enabled=true
|
||||||
|
YARN_CONF_yarn_timeline___service_hostname=historyserver
|
||||||
|
YARN_CONF_mapreduce_map_output_compress=true
|
||||||
|
YARN_CONF_mapred_map_output_compress_codec=org.apache.hadoop.io.compress.SnappyCodec
|
||||||
|
YARN_CONF_yarn_nodemanager_resource_memory___mb=16384
|
||||||
|
YARN_CONF_yarn_nodemanager_resource_cpu___vcores=8
|
||||||
|
YARN_CONF_yarn_nodemanager_disk___health___checker_max___disk___utilization___per___disk___percentage=98.5
|
||||||
|
YARN_CONF_yarn_nodemanager_remote___app___log___dir=/app-logs
|
||||||
|
YARN_CONF_yarn_nodemanager_aux___services=mapreduce_shuffle
|
||||||
|
|
||||||
|
MAPRED_CONF_mapreduce_framework_name=yarn
|
||||||
|
MAPRED_CONF_mapred_child_java_opts=-Xmx4096m
|
||||||
|
MAPRED_CONF_mapreduce_map_memory_mb=4096
|
||||||
|
MAPRED_CONF_mapreduce_reduce_memory_mb=8192
|
||||||
|
MAPRED_CONF_mapreduce_map_java_opts=-Xmx3072m
|
||||||
|
MAPRED_CONF_mapreduce_reduce_java_opts=-Xmx6144m
|
||||||
|
MAPRED_CONF_yarn_app_mapreduce_am_env=HADOOP_MAPRED_HOME=/opt/hadoop-3.4.1/
|
||||||
|
MAPRED_CONF_mapreduce_map_env=HADOOP_MAPRED_HOME=/opt/hadoop-3.4.1/
|
||||||
|
MAPRED_CONF_mapreduce_reduce_env=HADOOP_MAPRED_HOME=/opt/hadoop-3.4.1/
|
||||||
Reference in New Issue
Block a user