Compare commits
	
		
			No commits in common. "03d3d272df42567542f68893346adb94b7bae37b" and "6422189f6c2dabf3e5e33966cdf888603ac4ff0d" have entirely different histories.
		
	
	
		
			03d3d272df
			...
			6422189f6c
		
	
		
					 7 changed files with 73 additions and 924 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
/* login.css */
 | 
			
		||||
* {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,517 +0,0 @@
 | 
			
		|||
* {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-page {
 | 
			
		||||
  min-height: 100vh;
 | 
			
		||||
  background: linear-gradient(135deg, #0c0c0c 0%, #1a1a2e 50%, #16213e 100%);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-bg {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background: radial-gradient(circle at 20% 80%, rgba(0, 212, 255, 0.05) 0%, transparent 50%),
 | 
			
		||||
              radial-gradient(circle at 80% 20%, rgba(124, 58, 237, 0.05) 0%, transparent 50%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.floating-elements {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.floating-element {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 3px;
 | 
			
		||||
  height: 3px;
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
  animation: float 8s ease-in-out infinite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes float {
 | 
			
		||||
  0%, 100% { 
 | 
			
		||||
    transform: translateY(0px) rotate(0deg); 
 | 
			
		||||
    opacity: 0.3; 
 | 
			
		||||
  }
 | 
			
		||||
  50% { 
 | 
			
		||||
    transform: translateY(-30px) rotate(180deg); 
 | 
			
		||||
    opacity: 0.8; 
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-container {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  max-width: 480px;
 | 
			
		||||
  padding: 2rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-card {
 | 
			
		||||
  background: rgba(255, 255, 255, 0.08);
 | 
			
		||||
  backdrop-filter: blur(20px);
 | 
			
		||||
  border: 1px solid rgba(255, 255, 255, 0.1);
 | 
			
		||||
  border-radius: 24px;
 | 
			
		||||
  padding: 3rem;
 | 
			
		||||
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
 | 
			
		||||
  animation: slideInUp 0.8s ease-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes slideInUp {
 | 
			
		||||
  from {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: translateY(50px);
 | 
			
		||||
  }
 | 
			
		||||
  to {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    transform: translateY(0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-header {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-bottom: 2.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logo {
 | 
			
		||||
  font-size: 2rem;
 | 
			
		||||
  font-weight: 800;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logo-accent {
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
  background-clip: text;
 | 
			
		||||
  -webkit-background-clip: text;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-title {
 | 
			
		||||
  font-size: 1.75rem;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  margin-bottom: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-subtitle {
 | 
			
		||||
  color: #a0a0a0;
 | 
			
		||||
  font-size: 0.95rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  gap: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-row {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  gap: 0.5rem;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group.half-width {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  margin-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-label {
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  font-size: 0.9rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input-wrapper {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input-icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 1rem;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translateY(-50%);
 | 
			
		||||
  color: #888;
 | 
			
		||||
  font-size: 0.9rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-input {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 1rem 1rem 1rem 2.75rem;
 | 
			
		||||
  background: rgba(255, 255, 255, 0.05);
 | 
			
		||||
  border: 2px solid rgba(255, 255, 255, 0.1);
 | 
			
		||||
  border-radius: 12px;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
  transition: all 0.3s ease;
 | 
			
		||||
  backdrop-filter: blur(10px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-input:focus {
 | 
			
		||||
  outline: none;
 | 
			
		||||
  border-color: #00d4ff;
 | 
			
		||||
  box-shadow: 0 0 20px rgba(0, 212, 255, 0.2);
 | 
			
		||||
  background: rgba(255, 255, 255, 0.08);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-input.error {
 | 
			
		||||
  border-color: #ff4757;
 | 
			
		||||
  box-shadow: 0 0 20px rgba(255, 71, 87, 0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-input::placeholder {
 | 
			
		||||
  color: #666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.password-toggle {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 1rem;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translateY(-50%);
 | 
			
		||||
  background: none;
 | 
			
		||||
  border: none;
 | 
			
		||||
  color: #888;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  padding: 0.25rem;
 | 
			
		||||
  transition: color 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.password-toggle:hover {
 | 
			
		||||
  color: #00d4ff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.password-strength {
 | 
			
		||||
  margin-top: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-bar {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 4px;
 | 
			
		||||
  background-color: rgba(255, 255, 255, 0.1);
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  margin-bottom: 0.25rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-fill {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  transition: width 0.3s ease, background-color 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-fill.weak {
 | 
			
		||||
  background: linear-gradient(45deg, #ff4757, #ff6b7a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-fill.fair {
 | 
			
		||||
  background: linear-gradient(45deg, #ffa502, #ffb347);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-fill.good {
 | 
			
		||||
  background: linear-gradient(45deg, #2ed573, #7bed9f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-fill.strong {
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-text {
 | 
			
		||||
  font-size: 0.75rem;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-text.weak {
 | 
			
		||||
  color: #ff4757;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-text.fair {
 | 
			
		||||
  color: #ffa502;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-text.good {
 | 
			
		||||
  color: #2ed573;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.strength-text.strong {
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
  background-clip: text;
 | 
			
		||||
  -webkit-background-clip: text;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.password-mismatch {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  gap: 0.5rem;
 | 
			
		||||
  margin-top: 0.5rem;
 | 
			
		||||
  font-size: 0.75rem;
 | 
			
		||||
  color: #ff4757;
 | 
			
		||||
  animation: shake 0.5s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-options {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  gap: 1rem;
 | 
			
		||||
  margin-bottom: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-wrapper {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  gap: 0.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-input {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-custom {
 | 
			
		||||
  width: 18px;
 | 
			
		||||
  height: 18px;
 | 
			
		||||
  border: 2px solid rgba(255, 255, 255, 0.3);
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  transition: all 0.3s ease;
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  margin-top: 1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-input:checked + .checkbox-custom {
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
  border-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-input:checked + .checkbox-custom::after {
 | 
			
		||||
  content: '✓';
 | 
			
		||||
  color: white;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-label {
 | 
			
		||||
  color: #a0a0a0;
 | 
			
		||||
  font-size: 0.9rem;
 | 
			
		||||
  line-height: 1.4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.link {
 | 
			
		||||
  color: #00d4ff;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  transition: color 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.link:hover {
 | 
			
		||||
  color: #7c3aed;
 | 
			
		||||
  text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 1rem;
 | 
			
		||||
  background: linear-gradient(45deg, #00d4ff, #7c3aed);
 | 
			
		||||
  color: white;
 | 
			
		||||
  border: none;
 | 
			
		||||
  border-radius: 12px;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 1.1rem;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  transition: all 0.3s ease;
 | 
			
		||||
  margin-top: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-button:hover:not(:disabled) {
 | 
			
		||||
  transform: translateY(-2px);
 | 
			
		||||
  box-shadow: 0 15px 40px rgba(0, 212, 255, 0.4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.signup-button:disabled {
 | 
			
		||||
  opacity: 0.5;
 | 
			
		||||
  cursor: not-allowed;
 | 
			
		||||
  transform: none;
 | 
			
		||||
  background: rgba(255, 255, 255, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.loading-text {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  gap: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.divider {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin: 1.5rem 0;
 | 
			
		||||
  color: #666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.divider::before {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  height: 1px;
 | 
			
		||||
  background: rgba(255, 255, 255, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.divider span {
 | 
			
		||||
  background: rgba(255, 255, 255, 0.08);
 | 
			
		||||
  padding: 0 1rem;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.social-signup {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 0.875rem;
 | 
			
		||||
  background: rgba(255, 255, 255, 0.05);
 | 
			
		||||
  border: 2px solid rgba(255, 255, 255, 0.1);
 | 
			
		||||
  border-radius: 12px;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  transition: all 0.3s ease;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  gap: 0.75rem;
 | 
			
		||||
  margin-bottom: 0.75rem;
 | 
			
		||||
  backdrop-filter: blur(10px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.social-signup:hover {
 | 
			
		||||
  background: rgba(255, 255, 255, 0.08);
 | 
			
		||||
  border-color: rgba(255, 255, 255, 0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.social-signup.google:hover {
 | 
			
		||||
  border-color: rgba(219, 68, 55, 0.5);
 | 
			
		||||
  box-shadow: 0 0 20px rgba(219, 68, 55, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.social-signup.github:hover {
 | 
			
		||||
  border-color: rgba(255, 255, 255, 0.5);
 | 
			
		||||
  box-shadow: 0 0 20px rgba(255, 255, 255, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.error-message {
 | 
			
		||||
  background: rgba(255, 71, 87, 0.1);
 | 
			
		||||
  border: 1px solid rgba(255, 71, 87, 0.3);
 | 
			
		||||
  border-radius: 12px;
 | 
			
		||||
  padding: 1rem;
 | 
			
		||||
  color: #ff4757;
 | 
			
		||||
  font-size: 0.9rem;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  gap: 0.5rem;
 | 
			
		||||
  margin-top: 1rem;
 | 
			
		||||
  animation: shake 0.5s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.success-message {
 | 
			
		||||
  background: rgba(46, 213, 115, 0.1);
 | 
			
		||||
  border: 1px solid rgba(46, 213, 115, 0.3);
 | 
			
		||||
  border-radius: 12px;
 | 
			
		||||
  padding: 1rem;
 | 
			
		||||
  color: #2ed573;
 | 
			
		||||
  font-size: 0.9rem;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  gap: 0.5rem;
 | 
			
		||||
  margin-top: 1rem;
 | 
			
		||||
  animation: slideInUp 0.5s ease-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes shake {
 | 
			
		||||
  0%, 100% { transform: translateX(0); }
 | 
			
		||||
  25% { transform: translateX(-5px); }
 | 
			
		||||
  75% { transform: translateX(5px); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-prompt {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-top: 2rem;
 | 
			
		||||
  padding-top: 2rem;
 | 
			
		||||
  border-top: 1px solid rgba(255, 255, 255, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-prompt p {
 | 
			
		||||
  color: #a0a0a0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-link {
 | 
			
		||||
  color: #00d4ff;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  transition: color 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-link:hover {
 | 
			
		||||
  color: #7c3aed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Responsive */
 | 
			
		||||
@media (max-width: 640px) {
 | 
			
		||||
  .signup-container {
 | 
			
		||||
    padding: 1rem;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .signup-card {
 | 
			
		||||
    padding: 2rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .form-row {
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    gap: 0;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .form-group.half-width {
 | 
			
		||||
    margin-bottom: 1rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .checkbox-wrapper {
 | 
			
		||||
    align-items: flex-start;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .checkbox-label {
 | 
			
		||||
    font-size: 0.85rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 480px) {
 | 
			
		||||
  .signup-card {
 | 
			
		||||
    padding: 1.5rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .signup-title {
 | 
			
		||||
    font-size: 1.5rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .logo {
 | 
			
		||||
    font-size: 1.75rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +1,19 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="homepage">
 | 
			
		||||
    <!-- Navigation -->
 | 
			
		||||
    <nav class="navbar">
 | 
			
		||||
      <div class="nav-content">
 | 
			
		||||
        <div class="logo" @click="scrollTo('hero')">
 | 
			
		||||
          Ride<span class="logo-accent">Aware</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="nav-links">
 | 
			
		||||
          <li>
 | 
			
		||||
            <a href="#" @click.prevent="scrollTo('features')">Features</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <router-link to="/login" class="login-link">Login</router-link>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <router-link to="/signup" class="signup-btn">Sign Up</router-link>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li><a href="#" @click.prevent="scrollTo('features')">Features</a></li>
 | 
			
		||||
          <li><a href="/newsletters" @click.prevent="goToNewsletters">Newsletters</a></li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
 | 
			
		||||
    <!-- Hero Section -->
 | 
			
		||||
    <section id="hero" class="hero">
 | 
			
		||||
      <div class="hero-bg"></div>
 | 
			
		||||
      <div class="floating-elements">
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +72,7 @@
 | 
			
		|||
      </div>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <!-- Features Section -->
 | 
			
		||||
    <section id="features" class="features">
 | 
			
		||||
      <div class="section-header">
 | 
			
		||||
        <h2 class="section-title">{{ featuresTitle }}</h2>
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +101,7 @@
 | 
			
		|||
      </div>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <!-- Stats Section -->
 | 
			
		||||
    <section class="stats">
 | 
			
		||||
      <div class="container">
 | 
			
		||||
        <div class="stats-grid">
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +113,7 @@
 | 
			
		|||
      </div>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <!-- Footer -->
 | 
			
		||||
    <footer class="footer">
 | 
			
		||||
      <div class="container">
 | 
			
		||||
        <div class="footer-content">
 | 
			
		||||
| 
						 | 
				
			
			@ -227,6 +225,7 @@ export default {
 | 
			
		|||
    const animatedStats = reactive({})
 | 
			
		||||
    const floatingElements = reactive([])
 | 
			
		||||
 | 
			
		||||
    // Generate floating elements
 | 
			
		||||
    const generateFloatingElements = () => {
 | 
			
		||||
      for (let i = 0; i < 15; i++) {
 | 
			
		||||
        floatingElements.push({
 | 
			
		||||
| 
						 | 
				
			
			@ -240,6 +239,7 @@ export default {
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Animate stats on scroll
 | 
			
		||||
    const animateStats = () => {
 | 
			
		||||
      platformStats.forEach(stat => {
 | 
			
		||||
        let current = 0
 | 
			
		||||
| 
						 | 
				
			
			@ -264,11 +264,14 @@ export default {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    const goToNewsletters = () => {
 | 
			
		||||
      // Handle navigation to newsletters page
 | 
			
		||||
      // This could be a router push in a real Vue app
 | 
			
		||||
      window.location.href = '/newsletters'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const handleNotifyMe = () => {
 | 
			
		||||
      if (isValidEmail.value) {
 | 
			
		||||
        // Here you would typically send the email to your backend
 | 
			
		||||
        alert(`Thanks! We'll notify you at ${emailInput.value} when RideAware launches.`)
 | 
			
		||||
        emailInput.value = ''
 | 
			
		||||
      } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +293,7 @@ export default {
 | 
			
		|||
    onMounted(() => {
 | 
			
		||||
      generateFloatingElements()
 | 
			
		||||
      
 | 
			
		||||
      // Intersection Observer for stats animation
 | 
			
		||||
      const observer = new IntersectionObserver((entries) => {
 | 
			
		||||
        entries.forEach(entry => {
 | 
			
		||||
          if (entry.isIntersecting) {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,6 +308,7 @@ export default {
 | 
			
		|||
        observer.observe(statsSection)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Parallax effect for hero background
 | 
			
		||||
      window.addEventListener('scroll', () => {
 | 
			
		||||
        const scrolled = window.pageYOffset
 | 
			
		||||
        const parallax = document.querySelector('.hero-bg')
 | 
			
		||||
| 
						 | 
				
			
			@ -313,6 +318,7 @@ export default {
 | 
			
		|||
        }
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      // Animate mockup stats
 | 
			
		||||
      let statIndex = 0
 | 
			
		||||
      setInterval(() => {
 | 
			
		||||
        activeStat.value = mockupStats[statIndex].id
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								src/components/LoggedinPage.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/components/LoggedinPage.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div class="logged-in">
 | 
			
		||||
      <h2>You have successfully logged in!</h2>
 | 
			
		||||
      <p>Welcome back to RideAware!</p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </template>
 | 
			
		||||
  
 | 
			
		||||
  <script>
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'LoggedInPage',
 | 
			
		||||
  };
 | 
			
		||||
  </script>
 | 
			
		||||
  
 | 
			
		||||
  <style scoped>
 | 
			
		||||
  .logged-in {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
  }
 | 
			
		||||
  </style>
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="login-page">
 | 
			
		||||
    <!-- Background Elements -->
 | 
			
		||||
    <div class="login-bg">
 | 
			
		||||
      <div class="floating-elements">
 | 
			
		||||
        <div 
 | 
			
		||||
| 
						 | 
				
			
			@ -11,8 +12,10 @@
 | 
			
		|||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Login Container -->
 | 
			
		||||
    <div class="login-container">
 | 
			
		||||
      <div class="login-card">
 | 
			
		||||
        <!-- Logo/Header -->
 | 
			
		||||
        <div class="login-header">
 | 
			
		||||
          <div class="logo">
 | 
			
		||||
            Ride<span class="logo-accent">Aware</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +24,7 @@
 | 
			
		|||
          <p class="login-subtitle">Sign in to continue your cycling journey</p>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- Login Form -->
 | 
			
		||||
        <form @submit.prevent="login" class="login-form">
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <label for="username" class="form-label">Username</label>
 | 
			
		||||
| 
						 | 
				
			
			@ -73,18 +77,14 @@
 | 
			
		|||
          <button 
 | 
			
		||||
            type="submit" 
 | 
			
		||||
            class="login-button"
 | 
			
		||||
            :class="{ 'loading': isLoading, 'success': loginSuccess }"
 | 
			
		||||
            :class="{ 'loading': isLoading }"
 | 
			
		||||
            :disabled="isLoading"
 | 
			
		||||
          >
 | 
			
		||||
            <span v-if="!isLoading && !loginSuccess">Sign In</span>
 | 
			
		||||
            <span v-else-if="isLoading" class="loading-text">
 | 
			
		||||
            <span v-if="!isLoading">Sign In</span>
 | 
			
		||||
            <span v-else class="loading-text">
 | 
			
		||||
              <i class="fas fa-spinner fa-spin"></i>
 | 
			
		||||
              Signing In...
 | 
			
		||||
            </span>
 | 
			
		||||
            <span v-else-if="loginSuccess" class="success-text">
 | 
			
		||||
              <i class="fas fa-check"></i>
 | 
			
		||||
              Success! Redirecting...
 | 
			
		||||
            </span>
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <div class="divider">
 | 
			
		||||
| 
						 | 
				
			
			@ -102,16 +102,13 @@
 | 
			
		|||
          </button>
 | 
			
		||||
        </form>
 | 
			
		||||
 | 
			
		||||
        <!-- Error Message -->
 | 
			
		||||
        <div v-if="error" class="error-message">
 | 
			
		||||
          <i class="fas fa-exclamation-triangle"></i>
 | 
			
		||||
          {{ error }}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div v-if="loginSuccess" class="success-message">
 | 
			
		||||
          <i class="fas fa-check-circle"></i>
 | 
			
		||||
          Login successful! Redirecting to homepage...
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- Sign Up Link -->
 | 
			
		||||
        <div class="signup-prompt">
 | 
			
		||||
          <p>Don't have an account? <a href="/signup" class="signup-link">Sign up</a></p>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +129,6 @@ export default {
 | 
			
		|||
      password: '',
 | 
			
		||||
      error: null,
 | 
			
		||||
      isLoading: false,
 | 
			
		||||
      loginSuccess: false,
 | 
			
		||||
      showPassword: false,
 | 
			
		||||
      rememberMe: false,
 | 
			
		||||
      floatingElements: []
 | 
			
		||||
| 
						 | 
				
			
			@ -150,35 +146,26 @@ export default {
 | 
			
		|||
 | 
			
		||||
      this.isLoading = true;
 | 
			
		||||
      this.error = null;
 | 
			
		||||
      this.loginSuccess = false;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const response = await axios.post('http://localhost:5000/auth/login', {
 | 
			
		||||
        const response = await axios.post('http://127.0.0.1:5000/login', {
 | 
			
		||||
          username: this.username,
 | 
			
		||||
          password: this.password,
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        console.log('Login successful:', response.data);
 | 
			
		||||
        
 | 
			
		||||
        const userData = {
 | 
			
		||||
          user_id: response.data.user_id,
 | 
			
		||||
          username: this.username,
 | 
			
		||||
          loginTime: new Date().toISOString()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Store user data if remember me is checked
 | 
			
		||||
        if (this.rememberMe) {
 | 
			
		||||
          localStorage.setItem('user', JSON.stringify(userData));
 | 
			
		||||
          localStorage.setItem('authToken', 'authenticated');
 | 
			
		||||
          localStorage.setItem('user', JSON.stringify(response.data));
 | 
			
		||||
        } else {
 | 
			
		||||
          sessionStorage.setItem('user', JSON.stringify(userData));
 | 
			
		||||
          sessionStorage.setItem('authToken', 'authenticated');
 | 
			
		||||
          sessionStorage.setItem('user', JSON.stringify(response.data));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        this.loginSuccess = true;
 | 
			
		||||
        
 | 
			
		||||
        // Add success animation before redirect
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.$router.push('/');
 | 
			
		||||
        }, 1500);
 | 
			
		||||
          this.$router.push('/logged-in');
 | 
			
		||||
        }, 500);
 | 
			
		||||
        
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error('Login failed:', error.response?.data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,344 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="signup-page">
 | 
			
		||||
    <div class="signup-bg">
 | 
			
		||||
      <div class="floating-elements">
 | 
			
		||||
        <div 
 | 
			
		||||
          v-for="(element, index) in floatingElements" 
 | 
			
		||||
          :key="index"
 | 
			
		||||
          class="floating-element"
 | 
			
		||||
          :style="element.style">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="signup-container">
 | 
			
		||||
      <div class="signup-card">
 | 
			
		||||
        <div class="signup-header">
 | 
			
		||||
          <div class="logo">
 | 
			
		||||
            Ride<span class="logo-accent">Aware</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <h2 class="signup-title">Join RideAware</h2>
 | 
			
		||||
          <p class="signup-subtitle">Create your account to start tracking your cycling journey</p>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <form @submit.prevent="signup" class="signup-form">
 | 
			
		||||
          <div class="form-row">
 | 
			
		||||
            <div class="form-group half-width">
 | 
			
		||||
              <label for="firstName" class="form-label">First Name</label>
 | 
			
		||||
              <div class="input-wrapper">
 | 
			
		||||
                <i class="fas fa-user input-icon"></i>
 | 
			
		||||
                <input 
 | 
			
		||||
                  type="text" 
 | 
			
		||||
                  id="firstName" 
 | 
			
		||||
                  v-model="firstName" 
 | 
			
		||||
                  class="form-input"
 | 
			
		||||
                  :class="{ 'error': error && !firstName }"
 | 
			
		||||
                  placeholder="First name"
 | 
			
		||||
                  required 
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="form-group half-width">
 | 
			
		||||
              <label for="lastName" class="form-label">Last Name</label>
 | 
			
		||||
              <div class="input-wrapper">
 | 
			
		||||
                <i class="fas fa-user input-icon"></i>
 | 
			
		||||
                <input 
 | 
			
		||||
                  type="text" 
 | 
			
		||||
                  id="lastName" 
 | 
			
		||||
                  v-model="lastName" 
 | 
			
		||||
                  class="form-input"
 | 
			
		||||
                  :class="{ 'error': error && !lastName }"
 | 
			
		||||
                  placeholder="Last name"
 | 
			
		||||
                  required 
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <label for="username" class="form-label">Username</label>
 | 
			
		||||
            <div class="input-wrapper">
 | 
			
		||||
              <i class="fas fa-at input-icon"></i>
 | 
			
		||||
              <input 
 | 
			
		||||
                type="text" 
 | 
			
		||||
                id="username" 
 | 
			
		||||
                v-model="username" 
 | 
			
		||||
                class="form-input"
 | 
			
		||||
                :class="{ 'error': error && !username }"
 | 
			
		||||
                placeholder="Choose a username"
 | 
			
		||||
                required 
 | 
			
		||||
              />
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <label for="email" class="form-label">Email</label>
 | 
			
		||||
            <div class="input-wrapper">
 | 
			
		||||
              <i class="fas fa-envelope input-icon"></i>
 | 
			
		||||
              <input 
 | 
			
		||||
                type="email" 
 | 
			
		||||
                id="email" 
 | 
			
		||||
                v-model="email" 
 | 
			
		||||
                class="form-input"
 | 
			
		||||
                :class="{ 'error': error && !email }"
 | 
			
		||||
                placeholder="Enter your email"
 | 
			
		||||
                required 
 | 
			
		||||
              />
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <label for="password" class="form-label">Password</label>
 | 
			
		||||
            <div class="input-wrapper">
 | 
			
		||||
              <i class="fas fa-lock input-icon"></i>
 | 
			
		||||
              <input 
 | 
			
		||||
                :type="showPassword ? 'text' : 'password'" 
 | 
			
		||||
                id="password" 
 | 
			
		||||
                v-model="password" 
 | 
			
		||||
                class="form-input"
 | 
			
		||||
                :class="{ 'error': error && !password }"
 | 
			
		||||
                placeholder="Create a password"
 | 
			
		||||
                required 
 | 
			
		||||
              />
 | 
			
		||||
              <button 
 | 
			
		||||
                type="button" 
 | 
			
		||||
                class="password-toggle"
 | 
			
		||||
                @click="showPassword = !showPassword"
 | 
			
		||||
              >
 | 
			
		||||
                <i :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="password-strength" v-if="password">
 | 
			
		||||
              <div class="strength-bar">
 | 
			
		||||
                <div 
 | 
			
		||||
                  class="strength-fill" 
 | 
			
		||||
                  :class="passwordStrength.class"
 | 
			
		||||
                  :style="{ width: passwordStrength.width }"
 | 
			
		||||
                ></div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <span class="strength-text" :class="passwordStrength.class">
 | 
			
		||||
                {{ passwordStrength.text }}
 | 
			
		||||
              </span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <label for="confirmPassword" class="form-label">Confirm Password</label>
 | 
			
		||||
            <div class="input-wrapper">
 | 
			
		||||
              <i class="fas fa-lock input-icon"></i>
 | 
			
		||||
              <input 
 | 
			
		||||
                :type="showConfirmPassword ? 'text' : 'password'" 
 | 
			
		||||
                id="confirmPassword" 
 | 
			
		||||
                v-model="confirmPassword" 
 | 
			
		||||
                class="form-input"
 | 
			
		||||
                :class="{ 'error': error && !confirmPassword || passwordMismatch }"
 | 
			
		||||
                placeholder="Confirm your password"
 | 
			
		||||
                required 
 | 
			
		||||
              />
 | 
			
		||||
              <button 
 | 
			
		||||
                type="button" 
 | 
			
		||||
                class="password-toggle"
 | 
			
		||||
                @click="showConfirmPassword = !showConfirmPassword"
 | 
			
		||||
              >
 | 
			
		||||
                <i :class="showConfirmPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div v-if="passwordMismatch" class="password-mismatch">
 | 
			
		||||
              <i class="fas fa-exclamation-triangle"></i>
 | 
			
		||||
              Passwords do not match
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-options">
 | 
			
		||||
            <label class="checkbox-wrapper">
 | 
			
		||||
              <input type="checkbox" v-model="agreeToTerms" class="checkbox-input" required>
 | 
			
		||||
              <span class="checkbox-custom"></span>
 | 
			
		||||
              <span class="checkbox-label">
 | 
			
		||||
                I agree to the <a href="/terms" class="link">Terms of Service</a> 
 | 
			
		||||
                and <a href="/privacy" class="link">Privacy Policy</a>
 | 
			
		||||
              </span>
 | 
			
		||||
            </label>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="form-options">
 | 
			
		||||
            <label class="checkbox-wrapper">
 | 
			
		||||
              <input type="checkbox" v-model="subscribeNewsletter" class="checkbox-input">
 | 
			
		||||
              <span class="checkbox-custom"></span>
 | 
			
		||||
              <span class="checkbox-label">
 | 
			
		||||
                Subscribe to newsletter for cycling tips and updates
 | 
			
		||||
              </span>
 | 
			
		||||
            </label>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <button 
 | 
			
		||||
            type="submit" 
 | 
			
		||||
            class="signup-button"
 | 
			
		||||
            :class="{ 'loading': isLoading }"
 | 
			
		||||
            :disabled="isLoading || !isFormValid"
 | 
			
		||||
          >
 | 
			
		||||
            <span v-if="!isLoading">Create Account</span>
 | 
			
		||||
            <span v-else class="loading-text">
 | 
			
		||||
              <i class="fas fa-spinner fa-spin"></i>
 | 
			
		||||
              Creating Account...
 | 
			
		||||
            </span>
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <div class="divider">
 | 
			
		||||
            <span>or</span>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <button type="button" class="social-signup google">
 | 
			
		||||
            <i class="fab fa-google"></i>
 | 
			
		||||
            Sign up with Google
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <button type="button" class="social-signup github">
 | 
			
		||||
            <i class="fab fa-github"></i>
 | 
			
		||||
            Sign up with GitHub
 | 
			
		||||
          </button>
 | 
			
		||||
        </form>
 | 
			
		||||
 | 
			
		||||
        <div v-if="error" class="error-message">
 | 
			
		||||
          <i class="fas fa-exclamation-triangle"></i>
 | 
			
		||||
          {{ error }}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div v-if="successMessage" class="success-message">
 | 
			
		||||
          <i class="fas fa-check-circle"></i>
 | 
			
		||||
          {{ successMessage }}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="login-prompt">
 | 
			
		||||
          <p>Already have an account? <a href="/login" class="login-link">Sign in</a></p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import '@/assets/css/components/signup.css';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'UserSignup',
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      firstName: '',
 | 
			
		||||
      lastName: '',
 | 
			
		||||
      username: '',
 | 
			
		||||
      email: '',
 | 
			
		||||
      password: '',
 | 
			
		||||
      confirmPassword: '',
 | 
			
		||||
      error: null,
 | 
			
		||||
      successMessage: null,
 | 
			
		||||
      isLoading: false,
 | 
			
		||||
      showPassword: false,
 | 
			
		||||
      showConfirmPassword: false,
 | 
			
		||||
      agreeToTerms: false,
 | 
			
		||||
      subscribeNewsletter: false,
 | 
			
		||||
      floatingElements: []
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    passwordMismatch() {
 | 
			
		||||
      return this.confirmPassword && this.password !== this.confirmPassword;
 | 
			
		||||
    },
 | 
			
		||||
    passwordStrength() {
 | 
			
		||||
      if (!this.password) return { width: '0%', class: '', text: '' };
 | 
			
		||||
      
 | 
			
		||||
      let score = 0;
 | 
			
		||||
      let feedback = [];
 | 
			
		||||
      
 | 
			
		||||
      if (this.password.length >= 8) score += 1;
 | 
			
		||||
      else feedback.push('at least 8 characters');
 | 
			
		||||
      
 | 
			
		||||
      if (/[A-Z]/.test(this.password)) score += 1;
 | 
			
		||||
      else feedback.push('uppercase letter');
 | 
			
		||||
      
 | 
			
		||||
      if (/[a-z]/.test(this.password)) score += 1;
 | 
			
		||||
      else feedback.push('lowercase letter');
 | 
			
		||||
 | 
			
		||||
      if (/\d/.test(this.password)) score += 1;
 | 
			
		||||
      else feedback.push('number');
 | 
			
		||||
      
 | 
			
		||||
      if (/[!@#$%^&*(),.?":{}|<>]/.test(this.password)) score += 1;
 | 
			
		||||
      else feedback.push('special character');
 | 
			
		||||
      
 | 
			
		||||
      if (score < 2) {
 | 
			
		||||
        return { width: '25%', class: 'weak', text: 'Weak' };
 | 
			
		||||
      } else if (score < 4) {
 | 
			
		||||
        return { width: '50%', class: 'fair', text: 'Fair' };
 | 
			
		||||
      } else if (score < 5) {
 | 
			
		||||
        return { width: '75%', class: 'good', text: 'Good' };
 | 
			
		||||
      } else {
 | 
			
		||||
        return { width: '100%', class: 'strong', text: 'Strong' };
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    isFormValid() {
 | 
			
		||||
      return this.firstName && 
 | 
			
		||||
             this.lastName && 
 | 
			
		||||
             this.username && 
 | 
			
		||||
             this.email && 
 | 
			
		||||
             this.password && 
 | 
			
		||||
             this.confirmPassword && 
 | 
			
		||||
             !this.passwordMismatch && 
 | 
			
		||||
             this.agreeToTerms;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.generateFloatingElements();
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    async signup() {
 | 
			
		||||
      if (!this.isFormValid) {
 | 
			
		||||
        this.error = 'Please fill in all required fields correctly';
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.isLoading = true;
 | 
			
		||||
      this.error = null;
 | 
			
		||||
      this.successMessage = null;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const response = await axios.post('http://localhost:5000/auth/signup', {
 | 
			
		||||
          firstName: this.firstName,
 | 
			
		||||
          lastName: this.lastName,
 | 
			
		||||
          username: this.username,
 | 
			
		||||
          email: this.email,
 | 
			
		||||
          password: this.password,
 | 
			
		||||
          subscribeNewsletter: this.subscribeNewsletter
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        console.log('Signup successful:', response.data);
 | 
			
		||||
        
 | 
			
		||||
        this.successMessage = 'Account created successfully! Please check your email to verify your account.';
 | 
			
		||||
        
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.$router.push('/login');
 | 
			
		||||
        }, 2000);
 | 
			
		||||
        
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error('Signup failed:', error.response?.data);
 | 
			
		||||
        this.error = error.response?.data?.error || 'Account creation failed. Please try again.';
 | 
			
		||||
      } finally {
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    
 | 
			
		||||
    generateFloatingElements() {
 | 
			
		||||
      for (let i = 0; i < 12; i++) {
 | 
			
		||||
        this.floatingElements.push({
 | 
			
		||||
          style: {
 | 
			
		||||
            left: Math.random() * 100 + '%',
 | 
			
		||||
            top: Math.random() * 100 + '%',
 | 
			
		||||
            animationDelay: Math.random() * 8 + 's',
 | 
			
		||||
            animationDuration: (6 + Math.random() * 4) + 's'
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,46 +1,43 @@
 | 
			
		|||
import { createRouter, createWebHistory } from 'vue-router'
 | 
			
		||||
import { createRouter, createWebHistory } from 'vue-router';
 | 
			
		||||
 | 
			
		||||
// Lazy load components for better performance
 | 
			
		||||
const routes = [
 | 
			
		||||
  { 
 | 
			
		||||
    path: '/', 
 | 
			
		||||
    name: 'Home',
 | 
			
		||||
    component: () => import('../components/Home.vue'),
 | 
			
		||||
    meta: { title: 'RideAware – Home' } 
 | 
			
		||||
    component: () => import('../components/Home.vue') 
 | 
			
		||||
  },
 | 
			
		||||
  { 
 | 
			
		||||
    path: '/login', 
 | 
			
		||||
    name: 'Login',
 | 
			
		||||
    component: () => import('../components/UserLogin.vue'),
 | 
			
		||||
    meta: { title: 'RideAware – Sign In' } 
 | 
			
		||||
    component: () => import('../components/UserLogin.vue') 
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/signup',
 | 
			
		||||
    name: 'SignUp',
 | 
			
		||||
    component: () => import('../components/UserSignup.vue'),
 | 
			
		||||
    meta: { title: 'RideAware – Sign Up' }
 | 
			
		||||
  },
 | 
			
		||||
  
 | 
			
		||||
]
 | 
			
		||||
  { 
 | 
			
		||||
    path: '/logged-in', 
 | 
			
		||||
    name: 'LoggedIn',
 | 
			
		||||
    component: () => import('../components/LoggedinPage.vue'),
 | 
			
		||||
    // Optional: Add route guard to check if user is actually logged in
 | 
			
		||||
    meta: { requiresAuth: true }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const router = createRouter({
 | 
			
		||||
  history: createWebHistory(),
 | 
			
		||||
  routes,
 | 
			
		||||
})
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Optional: Navigation guard example
 | 
			
		||||
router.beforeEach((to, from, next) => {
 | 
			
		||||
  // Check if route requires authentication
 | 
			
		||||
  if (to.meta.requiresAuth) {
 | 
			
		||||
    const isLoggedIn = !!(localStorage.getItem('user') || sessionStorage.getItem('user'))
 | 
			
		||||
    // Check if user is logged in (implement your auth logic)
 | 
			
		||||
    const isLoggedIn = localStorage.getItem('user') || sessionStorage.getItem('user');
 | 
			
		||||
    if (!isLoggedIn) {
 | 
			
		||||
      next({ name: 'Login' })
 | 
			
		||||
      return
 | 
			
		||||
      next('/login');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  next()
 | 
			
		||||
})
 | 
			
		||||
  next();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.afterEach((to) => {
 | 
			
		||||
  const defaultTitle = 'RideAware'
 | 
			
		||||
  document.title = to.meta.title || defaultTitle
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default router
 | 
			
		||||
export default router;
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue